如何创建永远不会读取$ scope的$ scope函数?

时间:2015-12-03 15:44:17

标签: javascript html arrays angularjs angularjs-scope

我想创建一个$ scope函数,它只会操作它接收的变量。

我已经做了 working Plunker 来测试。

我有一个ng-repeat,它只列出了小猫的名字和id。我还有一个输入表单来接收新猫咪的名字。然后,我有3个按钮,每个按钮访问一个不同的$ scope函数,它将以不同的方式操作$ scope。

每个功能目标是从输入表单中读取kitty的名称读取猫咪上使用的最后一个ID 数组,将id + 1 分配给新的kitty,将新的kitty 推送到kitty数组并删除表单数据

  • 第一个功能$scope.addFullScope(), 将不会收到任何参数,并会阅读和操纵$scope

  • 中的所有内容
  • 第二个功能$scope.addJustDelete(kitty, kitties), 将同时接收新的kittykitties数组作为参数。但是,最后,要清理表单,它将执行$scope.kitty = undefined

  • 第三个功能$scope.addNoScope(kitty, kitties), 将同时接收新的kittykitties数组作为参数。但是,最后,为了清理表单,它将kitty = undefined但表单不会清理!并且所有内容都会出现问题。

如何使第三个函数或类似函数工作,这样我才能使用完全独立的函数?

  

附录:

HTML

  <body ng-app='app' ng-controller="ctrl">

    <h3 ng-repeat="kitty in kitties">
      {{kitty.name}}: {{kitty.id}} //Kitties list
    </h3>

    <input placeholder='Kitty name to add' class='form form-control' 
           type="text" ng-model="kitty.name" />

    <h3> $scope use on adding kitty:</h3>
    <button ng-click="addFullScope()">Full Scope.</button>
    <button ng-click="addJustDelete(kitty, kitties)">Just delete.</button>
    <button ng-click="addNoScope(kitty, kitties)">None. Buggy</button>
  </body>

控制器:

.controller('ctrl', function($scope) {
  $scope.kitties = [
    //Let's imagine kitties in here.
    {name: 'Purple kitty', id:35},
    //Kittie 36 died in a car accident. :(
    {name: 'Rodmentou cat', id: 37},
    {name: 'Fatty kitty', id: 38}

    ];

  $scope.addFullScope = function () {
    var size = $scope.kitties.length;
    var id = $scope.kitties[size-1].id + 1;

    $scope.kitty.id = id;
    $scope.kitties.push($scope.kitty);
    $scope.kitty = undefined;
  };

  $scope.addJustDelete = function (kitty, kitties) {
    var size = kitties.length;
    var id = kitties[size-1].id + 1;

    kitty.id = id;
    kitties.push(kitty);
    $scope.kitty= undefined;

  };

  $scope.addNoScope = function (kitty, kitties) {
    var size = kitties.length;
    var id = kitties[size-1].id + 1;

    kitty.id = id;
    kitties.push(kitty);
    kitty = undefined; //Don't work
  };



});

5 个答案:

答案 0 :(得分:9)

引擎盖下Angular需要一种方法来观察ngModel是否被更改并使用$ scope。$ watch来完成此任务。 $ watch被视为Equality Watcher,它会检查一个特定属性是否已更改,而不是基础上的对象是否已更改,这将是一个参考观察器。

我在Tero Parviainen's blog

上找到了一个很好的描述和形象

enter image description here

因此,您的代码的问题在于您正在设置kitty = undefined,但是ngModel和扩展名$ scope。$ watch正在kitty.name中寻找更改。为证明这种情况,我在kitty.name添加了一个手表,当您设置kitty = undefined时,手表永远不会被触发。将kitty设置为undefined会更改底层对象,但不会更改它的属性(非常令人困惑)!我创建了一个plunker example with updated code

<强> HTML

为了清楚起见,我创建了我们正在更新的模型kitten,因此它不会与我们正在迭代的kitties混淆。

<h3 ng-repeat="kitty in kitties">
  {{kitty.name}}: {{kitty.id}}
</h3>
<input placeholder='Kitty name to add' class='form form-control' type="text" ng-model="kitten.name" />
<h3> $scope use on adding kitty:</h3>
<button class='btn btn-success' ng-click="addNoScope(kitten, kitties)">None. Buggy</button>
<button class='btn btn-danger' ng-click="noWatch(kitten)">Full Scope.</button>

<强>的Javascript

最新的更新是从模型的小猫中创建克隆小猫,因此它不会在数组中引用。此外,当我们要重置模型的小猫时,我们会直接设置kitten.namekitten.id属性。

angular.module('app', [])
.controller('ctrl', function($scope) {

  $scope.kitten = {
    name: undefined, id: undefined
  };

  $scope.$watch('kitten.name', function() { console.log("changed"); }, true);

  $scope.kitties = [
    //Let's imagine kitties in here.
    {name: 'Purple kitty', id:35},
    //Kittie 36 died in a car accident. :(
    {name: 'Rodmentou cat', id: 37},
    {name: 'Fatty kitty', id: 38}

  ];

  $scope.addNoScope = function (kitten, kitties) {
    if (!$scope.kitten || !$scope.kitten.name) return;
    var size = kitties.length;
    var id = kitties[size-1].id + 1;
    var newKitten = {
      name: kitten.name, id: id
    }
    kitties.push(newKitten);
    kitten.name = undefined;
    kitten.id = undefined;
    // kitten = undefined;
  };

  $scope.noWatch = function (kitten) {
    kitten = undefined;
    console.log('not watching');
  };

});

答案 1 :(得分:3)

这是因为函数$scope.addNoScope(kitty, kitties)仅接收对象kitty的“引用副本”,因此更改引用仅影响此副本而不影响原始引用。 Check this thread.

因此,在您的情况下,$scope.kitty仍然指向具有姓氏和ID的同一对象。当您按addNoScope时,另一次有角度尝试再次推送同一个对象,因为角度不允许ng-repeat中的重复项,因此会track by,除非您添加kitty。< / p>

如果您需要在不使用范围的情况下执行此操作,解决方案是将包含var obj = {id:1}; function changeReference (obj){ //changing the reference to an entirely new object obj = {id:2} } function changeProperty (obj){ //changing a property of the current object obj.id = 2 } changeReference(obj); console.log(obj.id); //1 as original obj is not affected changeProperty(obj); console.log(obj.id); //2 的对象作为属性传递,以便在更改传递的对象的属性时,它会反映在原始对象上对象,如本例所示

$scope.addNoScope = function (fields, kitties) {
    var size = kitties.length;
    var id = kitties[size-1].id + 1;

    fields.kitty.id = id;
    kitties.push(fields.kitty);
    fields.kitty = undefined; //Don't work
  };

所以你的代码变成了

<input placeholder='Kitty name to add' class='form form-control' type="text" ng-model="fields.kitty.name" />
<h3> $scope use on adding kitty:</h3>
<button class='btn btn-danger' ng-click="addFullScope()">Full Scope.</button>
<button class='btn btn-warning' ng-click="addJustDelete(fields.kitty, kitties)">Just delete.</button>
<button class='btn btn-success' ng-click="addNoScope(fields, kitties)">None. Buggy</button>

和html

$scope.kitty

并且不要忘记在其他功能中将$scope.fields.kitty更改为std::cin,否则它们会中断。

答案 2 :(得分:2)

要使用独立的功能操作小猫,并使用单独的功能重置表单,请尝试:

  $scope.addNoScope = function (kitty, kitties) {
    manipulateKitties(kitty, kitties);
    resetForm();
  };

  function manipulateKitties(kitty, kitties) {
    var size = kitties.length;
    var id = kitties[size-1].id + 1;

    kitty.id = id;
    kitties.push(kitty);
  }

  function resetForm() {
    $scope.kitty= undefined;
  }

答案 3 :(得分:1)

这是不可能的,因为JS遵循Java的pass-by-ref-ish参数传递方法。这里有一些与你的案例相关的例子

(pen)

&#13;
&#13;
    function double(x) {
      x.val = 2 * x.val;
    }

    function doubleToo(x) {
      x = 2 * x;
    }

    var data = {
      val: 2
    };

    document.write("Initial: " + data.val + "<br />");

    double(data); //data.val now = 4

    document.write("Double: " + data.val + "<br />");

    doubleToo(data.val); //data.val is still 4

    document.write("DoubleToo:" + data.val);
&#13;
&#13;
&#13;

对参数的赋值操作对传入的实际变量没有影响。这就是为什么第一个更新对象内容的例子有效,第二个例子(尝试重新分配)价值全部在一起)没有。

因此,在您的情况下,如果该函数绝对必须更新$scope中的变量,则必须接收$scope作为参数(或包含对{{1}的引用的某个对象})。就像在该示例中一样,它必须接收$scope来更新data

答案 4 :(得分:0)

您只需按以下方式重构您的功能:

  $scope.addNoScope = function (kitty, kitties) {
    var size = kitties.length;

    kitties.push({ //you need to create a new object
      id : kitties[size-1].id + 1,
      name : kitty.name
    });
    kitty.name = undefined;   
};

重要的是要记住JavaScript是按值传递变量,这意味着参数kitty实际上是范围$ scope.kitty中的变量。所以你把实际的范围变量推送到你的数组中,然后使它等于undefined,这就是bug结果的原因。