2016-05-26 2 views
0

サーバーからのjsonに基づいてフォームを動的に作成するディレクティブを作成しました。私はng-model属性をさまざまな入力要素に追加しようとしているので、入力値を入力してsubmitをクリックした後に入力値を使用できるようになります。 ng-model属性が追加されているようですが、双方向データバインディングは機能しません。最初のコンパイル後に作成された要素の双方向バインディングの作成

EDIT:下図のように、私はリンク機能の中からbuildFormを呼んでいる:

function link(scope, elem, attr, ctrl) { 
    //asyc request to the server, data here is a json object from the server 
    getMovieDataStructure({ 
     onSuccess: (data) => { 
      scope.mdb = data; 
      buildForm(scope.mdb, elem); 
     }, 
     onFail: (res) => { 
      console.log("ERROR getting it"); 
     } 
    });    
} 

ここでは、ディレクティブ内からのコードの一部である:例えば

//mdb is an array of objects describing the form requirments 
function buildForm(mdb, formElement) { 
    for(var i=0; i < mdb.length; i++) { 
     if(mdb[i].type == 'string') { 
      if(mdb[i].maxLength && mdb[i].maxLength > 1024) { 
       //if maxLength > 1024 put a text area instead 
       formElement.append(createTextArea({ 
        id: mdb[i].fieldName, 
        placeholder: mdb[i].fieldName 
       })); 
      } else { 
       //add input field to the form 
       formElement.append(createTextInput({ 
        id: mdb[i].fieldName, 
        placeholder: mdb[i].fieldName 
       })); 
      } 
     } else if(){ 
      //some more cases 
     } 

     formElement.append("<br>"); 
    } 
    //...some more code... 
} 

//one of the functions to create an input element 
function createTextInput(data) { 
    var elem = angular.element("<input>"); 
    elem.attr("type", "text"); 
    elem.attr("id", data.id); 
    elem.attr("ng-model", data.id); 
    elem.attr("placeholder", data.placeholder); 

    return elem; 
} 

、 htmlページのinput要素の結果は次のようになります。

<input placeholder="movie_name" ng-model="movie_name" id="movie_name" type="text"> </input> 

そして、同じタグをhtmlファイルに直接書き込むと、双方向バインディングがうまく機能します。

ここには何が欠けていますか?これを行うには良い方法がありますか、私は物事を過度に複雑化していますか?

+0

あなたはサーバーからデータを取得するために '' '$ http'''を使用している場合、それは更新する必要がありますモデルは見える。 – Nivesh

答えて

0

、ディレクティブの依存関係のリストに追加されました。

ロング説明:

buildForm(scope.mdb,elem)は(そう、実際にbuildForm$compile(elem.contents())(scope);を追加するequivilantだろう)ディレクティブの要素を返し、角度wraped要素の.contents()は、その要素のすべての子を返します。 $compile(buildForm(scope.mdb, elem).contents())buildFormがそれにいくつかの要素を追加しました(そのうちのいくつかは、彼ら自身のディレクティブを持った後、ディレクティブの要素のすべての子をコンパイルするために、角伝えることを意味

.contents()ための呼び出しが重要です理由:

we only compile .childNodes so that we don't get into infinite loop compiling ourselves

https://docs.angularjs.org/api/ng/service/ $コンパイルから)

$compile()機能は、NEリンク機能を返しますリンクするスコープで呼び出されるeds。したがって、最後に(scope)を追加すると、返された関数が呼び出されます。そのコードを書くための

(やや少ないエレガントなが)もっと明確な方法、次のようになります。

var element = buildForm(scope.mdb, elem); //buildForm returns an angular wraped element 
var linking = $compile(element); // $compile returns a linking function 
linking(scope); //linking is functions that takes a scope object 
       //and needs to be run after compilation 
1

フォームを更新した後は、$ compileを呼び出す必要があります。それ以外の場合、角度は変更を認識しません。参照:

https://docs.angularjs.org/api/ng/service/ $あなたは多分buildformメソッドを呼び出した後、試して

+0

私はリンク関数からフォームを構築することを前に言及しませんでした。より意味をなさないでしょうか(そして、もし私がテンプレート関数からそれをやるなら、 '$ compile'を呼び出す必要性を省くでしょうか?) –

+1

テンプレート関数から行うことができるなら、テンプレート関数は文字列を返す必要がありますが、 DOMツリーではありません – Walfrat

0

何かが$ rootScope.apply()を呼び出すことであろうコンパイルします。何が起こっているのかは、ダイジェストサイクルが完了した後、DOMにこれらの変更をすべて加えているということです。次のサイクルが発生するまで角度が変化について知りません。

あなたのケースでは、次のようになります。 buildForm(scope.mdb、elem); スコープ。$ apply();

0

あなたのケースで明示的にダイジェストループを呼び出す必要があるのは、変更が行われたことに気づいていないためです。

使用します。

buildForm(scope.mdb, elem); 
scope.$apply(); 

OR

しかし、$を適用し使用するためのより良い方法があります:

scope.$apply(buildForm(scope.mdb,elem)); 

の違いは、最初のバージョンでは、我々は値を更新しているということです角度のコンテキストの外側にあるので、エラーが発生した場合、Angularは決して知りません。ディレクティブは、DOM要素を追加しているので、それは角度が

短い答えがラインbuildForm(scope.mdb, elem);$compile(buildForm(scope.mdb, elem).contents())(scope);に変更されていると'$compile'があったことである変化を認識するようにする後でコンパイルする必要があります言及wdandaとして

+0

次のエラーが発生しています:http://errors.angularjs.org/1.5.3/$rootScope/inprog?p0=%24digest(2番目の方法でした。エラースタックトレースはその行) –

関連する問題