2016-10-10 16 views
1

私は単純なHTMLマークアップを持っていて、その中のビューモデルとテンプレートのリストを持っています。また、私は<pre>セクションで私のviewmodelを持っている:それは良い作品観測可能な配列の観察可能なビューモデルはKnockoutJsでは動作しません

<div class="container"> 
    <div class="row"> 
    <div class="col-md-6"> 
     <div class="col-md-12"> 
     <div class="panel panel-primary"> 
      <div class="panel-heading"> 
      Names 
      <button type="button" class="btn btn-link" data-bind="click: addName"> 
       <span class="glyphicon glyphicon-plus"></span> 
      </button> 
      </div> 
      <div class="panel-body"> 
      <ul class="list-group" id="namesList" data-bind="foreach: Names"> 
       <li class="list-group-item"><my-comp></my-comp></li> 
      </ul> 
      </div> 
     </div> 
     </div> 
    </div> 
    <div class="col-md-6"> 
     <div class="col-md-12"> 
     <pre data-bind="text: ko.toJSON(Names, null, 2)"></pre> 
     </div> 
    </div> 
    </div> 
</div> 
<script type="text/html" id="fullNameTmpl"> 
    <p>First name: <strong data-bind="text: firstName"></strong></p> 
    <p>Last name: <strong data-bind="text: lastName"></strong></p> 

    <p>First name: <input data-bind="textInput: firstName" /></p> 
    <p>Last name: <input data-bind="textInput: lastName" /></p> 

    <p>Full name: <input data-bind="textInput: fullName"></p> 

    <button data-bind="click: capitalizeLastName">Go caps</button> 
</script> 
<script> 
    function AppViewModel() { 
    var self = this; 
    self.firstName = ko.observable("Bert"); 
    self.lastName = ko.observable("Bertington"); 

    this.fullName = ko.pureComputed({ 
     read: function() { 
     return self.firstName() + " " + self.lastName(); 
     }, 
     write: function (value) { 
     var lastSpacePos = value.lastIndexOf(" "); 
     if (lastSpacePos > 0) { 
      self.firstName(value.substring(0, lastSpacePos)); 
      self.lastName(value.substring(lastSpacePos + 1)); 
     } 
     }, 
     owner: self 
    }); 

    self.capitalizeLastName = function() { 
     var currentVal = this.lastName();   
     this.lastName(currentVal.toUpperCase()); 
    }; 
    } 
    ko.components.register('my-comp', { 
    viewModel: AppViewModel, 
    template: { element: "fullNameTmpl" } 
    }); 

    function NamesViewModel() { 
    var self = this; 

    self.Names = ko.observableArray(); 

    self.addName = function() { 
     var vm = ko.observable(new AppViewModel()); 
     self.Names.push(vm); 
    } 
    } 

    ko.applyBindings(new NamesViewModel()); 
</script> 

、私はリストに項目を追加することができますし、これらの項目でデータバインディングが動作します。新しいAppViewModelを追加すると、<pre>セクションのNamesアレイに表示されます。問題は、新しい姓を入力するのと同じように、ネストされたビューモデルでいくつかの値を変更するときに、現在のビューモデルの<pre>セクションの変更がNames配列にないことです。

本当に観測可能な観測値の配列を作成するにはどうすればよいですか?このようなコンポーネントを追加する最も収益性の高い方法は何ですか?私はすでに観察可能なネストされたビューモデルを実行しましたが、うまくいかないようです。

+0

私はここでの問題は、プッシュのようなイベントに通知し、obversableとして配列自体を扱い、削除observableArrayそのノックアウトがあるが、配列内のアイテムの単一のプロパティ場合は通知しないだろうと思い変更。私はあなたがそれを自分で実装することを余儀なくされていると確信しています(ドキュメントには、これを非常に簡単に言及する "重要なポイント" http://knockoutjs.com/documentation/observableArraysがあります)。html) –

+0

@NickDeFazioですが、 'addName'メソッドでは、' ko.observable'を追加します。これで十分ですか? –

答えて

1

コードにいくつかの問題があります。この問題は、必ずしも観測可能な配列ではなく、コンポーネントを使用する際の問題です。コンポーネントの目的はhereです。注意すべき事項:

  1. 観測可能な配列要素は、作成する必要はありませんobservable。したがって、行う必要はありませんvar vm = ko.observable(new AppViewModel());単にvar vm = new AppViewModel();を使用し、あなたの配列を押してください。しかし、コンポーネントを使用したい場合は、このどちらかが正しくありません!基本的にAppViewModelsを2回アップしています!なぜ見えますか?上記の行で明示的に一度やってから、コンポーネントはそれを一度暗黙的に行います。コンポーネントが作成されるたびにAppViewModelに関連付けられます。これはコンポーネントの登録時に発生します。
  2. コンポーネントは、独自のプロパティ、機能、計算などを持つmini-viewModelと考えることができます。したがって、おそらくコンポーネントを使用する必要はありません.-あなたの<script></script>タグの内部をコピーして貼り付けます<li><li>に入っていて、うまくいくはずです。

これがあなたが探している答えであるかどうかはわかりませんが、これはあなたがしたいことを行うはずです。あなたが好きならコンポーネントを使うことができますが、あなたはもっと多くの変更や不必要な複雑さを必要とします。私はあなたの変数名を変更する自由を取った。私は彼らがこのようにもっと適切かもしれないと思う。お役に立てれば!

編集

私はコンポーネントで動作するようにコードスニペットを編集しました。この特定の実装の問題は、コンポーネントがobservableArrayという名前でAppViewModelと緊密に結合されていることです。これは大丈夫かもしれませんが、多くの場合、ビューモデルが大きくなり複雑になると、望ましくない動作につながることがよくあります。もちろん、デカップリングをよくするために、アンラップされた値firstNamelastNameを渡すこともできますが、<pre data-bind="text: ko.toJSON(names, null, 2)"></pre>はobservableArrayという名前の変更を登録しないため、正方形に戻ることになります。

ko.components.register('my-comp', { 
 
    viewModel: function(params) { 
 
    var self = this; 
 
    self.firstName = params.data.firstName 
 
    self.lastName = params.data.lastName 
 
    self.fullName = ko.pureComputed({ 
 
     read: function() { 
 
     return self.firstName() + " " + self.lastName(); 
 
     }, 
 
     write: function(value) { 
 
     var lastSpacePos = value.lastIndexOf(" "); 
 
     if (lastSpacePos > 0) { 
 
      self.firstName(value.substring(0, lastSpacePos)); 
 
      self.lastName(value.substring(lastSpacePos + 1)); 
 
     } 
 
     }, 
 
     owner: self 
 
    }); 
 

 
    self.capitalizeLastName = function() { 
 
     var str = self.lastName(); 
 
     self.lastName(str.toUpperCase()); 
 
    }; 
 
    }, 
 
    template: { 
 
    element: "fullNameTmpl" 
 
    } 
 
}); 
 

 
var Name = function(){ 
 
    this.firstName = ko.observable("Bert"); 
 
    this.lastName = ko.observable("McBertington"); 
 
} 
 

 

 
function AppViewModel() { 
 
    var self = this; 
 
    self.names = ko.observableArray(); 
 
    self.addName = function() { 
 
    self.names.push(new Name()); 
 
    } 
 
} 
 

 

 
ko.applyBindings(new AppViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 
 

 
Names 
 
<button type="button" class="btn btn-link" data-bind="click: addName"> 
 
    Add Dude 
 
</button> 
 

 
<ul class="list-group" id="namesList" data-bind="foreach: names"> 
 
    <my-comp params="data: $data"></my-comp> 
 
    <!--<li class="list-group-item"> 
 
    <p>First name: <strong data-bind="text: firstName"></strong></p> 
 
    <p>Last name: <strong data-bind="text: lastName"></strong></p> 
 
    <p>First name: <input data-bind="textInput: firstName" /></p> 
 
    <p>Last name: <input data-bind="textInput: lastName" /></p> 
 
    <p>Full name: <input data-bind="textInput: fullName"></p> 
 
    <button data-bind="click: capitalizeLastName">Go caps</button> 
 
    </li>--> 
 
</ul> 
 

 

 
<pre data-bind="text: ko.toJSON(names, null, 2)"></pre> 
 

 
<script type="text/html" id="fullNameTmpl"> 
 
    <li> 
 
    <p>First name: <strong data-bind="text: firstName"></strong></p> 
 
    <p>Last name: <strong data-bind="text: lastName"></strong></p> 
 
    <p>First name: <input data-bind="textInput: firstName" /></p> 
 
    <p>Last name: <input data-bind="textInput: lastName" /></p> 
 
    <p>Full name: <input data-bind="textInput: fullName"></p> 
 
    <button data-bind="click: capitalizeLastName">Go caps</button> 
 
    </li> 
 
</script>

+0

答えをありがとう!できます!しかし、最初のメモでは次のように述べました:_コンポーネントが作成されるたびにAppViewModelに関連付けられます。これはコンポーネントを登録すると起こります._どのように正しく登録してからコンポーネントを呼び出すことができますか?私の場合、コンポーネントを使用する必要があります。なぜなら、この名前エディタはどこでも使用する必要があるからです。私が理解している限り、コンポーネントに間違ったことがありますが、私には例を挙げてください。どうすれば私と一緒に作業できますか? –

+0

こんにちは、私は答えを更新しました。それがあなたを助けることを願っています –

+0

'Name'ビューモデルが必要な理由を理解できません。その目的は何ですか? –

関連する問題