99

私は2つのコントローラを持ち、それらの間にapp.factory関数でデータを共有します。AngularJS:モデル要素がモデル配列からスプライスされたとき、ng-repeatリストは更新されません

リンクがクリックされると、最初のコントローラがモデル配列(pluginsDisplayed)にウィジェットを追加します。ウィジェット(つまり配列コンテンツを表示するためNGリピートを使用して)アレイに押し込まれ、この変更がビューに反映されている:

<div ng-repeat="pluginD in pluginsDisplayed"> 
    <div k2plugin pluginname="{{pluginD.name}}" pluginid="{{pluginD.id}}"></div> 
</div> 

ウィジェットは、三のディレクティブ、k2plugin、削除およびサイズ変更に基づいて構築されています。 removeディレクティブは、k2pluginディレクティブのテンプレートにスパンを追加します。上記のスパンをクリックすると、共有配列の右要素がArray.splice()で削除されます。共有配列は正しく更新されますが、変更はではなく、がビューに反映されます。ただし、別の要素が追加されると、削除後、ビューは正しくリフレッシュされ、以前に削除された要素は表示されません。

何が間違っていますか?なぜこれがうまくいかないのか私に説明できますか? 私はAngularJSを使って何をしようとしているのですか?

これは私のindex.htmlです:

<!doctype html> 
<html> 
    <head> 
     <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.min.js"> 
     </script> 
     <script src="main.js"></script> 
    </head> 
    <body> 
     <div ng-app="livePlugins"> 
      <div ng-controller="pluginlistctrl"> 
       <span>Add one of {{pluginList.length}} plugins</span> 
       <li ng-repeat="plugin in pluginList"> 
        <span><a href="" ng-click="add()">{{plugin.name}}</a></span> 
       </li> 
      </div> 
      <div ng-controller="k2ctrl"> 
       <div ng-repeat="pluginD in pluginsDisplayed"> 
        <div k2plugin pluginname="{{pluginD.name}}" pluginid="{{pluginD.id}}"></div> 
       </div> 
      </div> 
     </div> 
    </body> 
</html> 

これは私のmain.jsです:

var app = angular.module ("livePlugins",[]); 

app.factory('Data', function() { 
    return {pluginsDisplayed: []}; 
}); 

app.controller ("pluginlistctrl", function ($scope, Data) { 
    $scope.pluginList = [{name: "plugin1"}, {name:"plugin2"}, {name:"plugin3"}]; 
    $scope.add = function() { 
     console.log ("Called add on", this.plugin.name, this.pluginList); 
     var newPlugin = {}; 
     newPlugin.id = this.plugin.name + '_' + (new Date()).getTime(); 
     newPlugin.name = this.plugin.name; 
     Data.pluginsDisplayed.push (newPlugin); 
    } 
}) 

app.controller ("k2ctrl", function ($scope, Data) { 
    $scope.pluginsDisplayed = Data.pluginsDisplayed; 

    $scope.remove = function (element) { 
     console.log ("Called remove on ", this.pluginid, element); 

     var len = $scope.pluginsDisplayed.length; 
     var index = -1; 

     // Find the element in the array 
     for (var i = 0; i < len; i += 1) { 
      if ($scope.pluginsDisplayed[i].id === this.pluginid) { 
       index = i; 
       break; 
      } 
     } 

     // Remove the element 
     if (index !== -1) { 
      console.log ("removing the element from the array, index: ", index); 
      $scope.pluginsDisplayed.splice(index,1); 
     } 

    } 
    $scope.resize = function() { 
     console.log ("Called resize on ", this.pluginid); 
    } 
}) 

app.directive("k2plugin", function() { 
    return { 
     restrict: "A", 
     scope: true, 
     link: function (scope, elements, attrs) { 
      console.log ("creating plugin"); 

      // This won't work immediately. Attribute pluginname will be undefined 
      // as soon as this is called. 
      scope.pluginname = "Loading..."; 
      scope.pluginid = attrs.pluginid; 

      // Observe changes to interpolated attribute 
      attrs.$observe('pluginname', function(value) { 
       console.log('pluginname has changed value to ' + value); 
       scope.pluginname = attrs.pluginname; 
      }); 

      // Observe changes to interpolated attribute 
      attrs.$observe('pluginid', function(value) { 
       console.log('pluginid has changed value to ' + value); 
       scope.pluginid = attrs.pluginid; 
      }); 
     }, 
     template: "<div>{{pluginname}} <span resize>_</span> <span remove>X</span>" + 
         "<div>Plugin DIV</div>" + 
        "</div>", 
     replace: true 
    }; 
}); 

app.directive("remove", function() { 
    return function (scope, element, attrs) { 
     element.bind ("mousedown", function() { 
      scope.remove(element); 
     }) 
    }; 

}); 

app.directive("resize", function() { 
    return function (scope, element, attrs) { 
     element.bind ("mousedown", function() { 
      scope.resize(element); 
     }) 
    }; 
}); 

答えて

130

あなたは、このようなとAjax呼び出しを行うなどAngularJS、外の操作のいくつかのフォームを行うたびjQuery、またはイベントを要素にバインドする場合は、AngularJSに自身を更新させる必要があるようにする必要があります。ここであなたがする必要があるコードが変更された:

app.directive("remove", function() { 
    return function (scope, element, attrs) { 
     element.bind ("mousedown", function() { 
      scope.remove(element); 
      scope.$apply(); 
     }) 
    }; 

}); 

app.directive("resize", function() { 
    return function (scope, element, attrs) { 
     element.bind ("mousedown", function() { 
      scope.resize(element); 
      scope.$apply(); 
     }) 
    }; 
}); 

ここでは、その上のドキュメントです:https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply

+4

$ applyに渡される式/関数内でscope.remove(element)およびscope.resize(element)を移動することを検討してください。 –

+1

@PerHornshøj-Schierbeck私は同意します。そうでなければ、Angularはエラーが発生してもエラーを認識しません。 –

+2

注意してください!通常、Angularコールはダイジェストサイクルを$とする必要があるときにそれを手動で呼び出します。最適化エラーが発生する可能性があり、リソースを消費する可能性があるため、手動で呼び出すことはしばしば悪い習慣です。 – Alex

53

あなたは$scope.pluginsDisplayed.splice(index,1);$scope.$apply();権利を追加した場合、それは動作します。

なぜこれが起こっているのかわかりませんが、AngularJSが$ scopeが変更されたことを知らないときは、$ applyを手動で呼び出す必要があります。私はAngularJSにも新しいので、これをもっとよく説明することはできません。私はあまりにもそれを見て必要があります。

this awesome article非常に適切に説明されています。 注:「mousedown」にバインドするのではなく、ng-click (docs)を使用する方が良いかもしれないと思います。私はAngularJSに基づいてここに単純なアプリ(http://avinash.me/losh、ソースhttp://github.com/hardfire/losh)を書いた。それは非常にきれいではありませんが、助けになるかもしれません。

7

私は同じ問題がありました。問題は 'ng-controller'が2回(ルーティングとHTMLで)定義されたためです。

0

これを行う簡単な方法があります。非常に簡単。私は

$scope.yourModel = []; 

は、あなたがこの

function deleteAnObjectByKey(objects, key) { 
    var clonedObjects = Object.assign({}, objects); 

    for (var x in clonedObjects) 
     if (clonedObjects.hasOwnProperty(x)) 
      if (clonedObjects[x].id == key) 
       delete clonedObjects[x]; 

    $scope.yourModel = clonedObjects; 
} 

のように$ scope.yourModelを行うことができ、すべての$ scope.yourModel配列リストはclonedObjectsで更新されます。削除されていることに気づいたので、

希望に役立ちます。

関連する問題