【问题标题】:AngularJS : Shared Service property not bound to controllersAngularJS:共享服务属性未绑定到控制器
【发布时间】:2014-12-09 13:46:23
【问题描述】:

(请尽量不要挂断在将其转移到这篇文章时可能发生的任何拼写错误或语义。我知道代码成功执行,所以我的问题不是拼写错误。另外,虽然我对其他方式感兴趣执行此任务 - 例如使用单个控制器 - 我更感兴趣的是为什么这个场景不起作用。它可能会再次出现,如果已经理解了这个问题会很好)

我正在尝试做一些我认为相当简单的事情,在遵循了几个教程和 Stack Overflow 帖子(以及其他地方)之后,我看不到我缺少什么。我希望一双新鲜的眼睛能有所帮助!

HTML 包含一个可以添加新产品的表单(为简洁起见,我减少了元素的数量)和一个显示产品的 P 标签列表......目标是将新产品添加到列表中一旦它们被创建,显然不需要刷新页面。

<div style="width: 300px; float: left; display: inline-block;" data-ng-controller="ProductFormCtrl" data-ng-model="svc">
    <p>
        Name:
        <input type="url" id="txProductName" data-ng-model="svc.form.productName"/>
    </p>

    <button id="btnSubmit" data-ng-click="svc.addNewProduct()">submit</button>
    {{ svc.Title }}
</div>

<div id="dvProductList" style="position:relative;float:left;" data-ng-controller="ProductListCtrl">
    <h2>{{ svc.Title }} </h2>
    <P data-ng-repeat="product in svc.products">{{ product.ProductName }}</P>
</div>

表单和列表由单独的控制器管理...每个控制器都引用一个 ProductService 及其 $scope 变量...

var app = angular.module('productApp', []);

app.controller('ProductFormCtrl', ['$scope', '$http', 'ProductService', function ($scope, $http, $productSvc) {

    $scope.svc = $productSvc;
    $scope.svc.Title = "Tea";
}]);
app.controller('ProductListCtrl', ['$scope', '$http', 'ProductService', function ($scope, $http, $productSvc) {

    $scope.svc = $productSvc;

}]);

为了引用列表,想到了将ProdcutListCtrl中的P元素绑定到ProductServiceproducts属性,当添加新产品时,只需更新 products 属性的内容,瞧! ……还是不……

服务定义了属性“products”,其值是通过调用 Web 服务来初始化的。它是一组轻量级产品对象。

app.service('ProductService', ['$http', function ($http) {

    var self = this;
    self.Title = "Coffee";
    //
    // initialize the property to be referenced by both controllers
    (function () {
        $http.get("/API/ProductAPI/GetUserProducts/36d43a01-22e5-494d-9e46-2d4ea5df7001")
            .success(function (data) {
                self.products = data;
            });
    })(); 
    //
    // object to hold the form values
    self.form = { productName: '' };
    //
    // calls web service to add a new product
    self.addNewProduct = function () {

        var formData = new FormData();
        formData.append('ProductName', self.form.productName);

        $.ajax({
            type: "POST",
            url: "/API/ProductAPI/AddUserProduct/36d43a01-22e5-494d-9e46-2d4ea5df7001",
            data: formData,
            processData: false,
            contentType: false
        })
            .done(function (data) {

                if (data != null) {
                //
                // These changes are not expressed in the User Interface
                    self.products.push(data);  // Update the products property with the new product
                    self.Title = "Completed";  // Update the title property 
                }
            });
    };
}]);

所以我的期望是,通过将新对象“推送”到现有数组中,引用“产品”属性的产品列表将自动更新。我什至在请求完成时更新 Title 属性并且该更改也没有显示在表单中。

  • 我知道新产品正在数据库中创建,甚至 它正在被退回......事实上,我已经确认 “self.products”属性甚至正在更新。

  • 我还认为,由于 SERVICE 实际上是一个实例化 可能正在传递 ProductService 的不同 instance 到每个控制器。我已经消除了这种可能性,因为我可以在一个控制器中更改属性 svc.Title 并看到它是 传播到另一个控制器(“咖啡”更改为“茶”)。

不管怎样……我似乎在某种程度上失去了对“自我”的提及。添加新产品的 AJAX 请求完成时的属性,我不确定为什么会这样。我欢迎任何想法或指导。

谢谢, -G

!!解决方案!!

感谢 shaunhusain 的解决方案...实际上非常简单的解决方案。我在服务中添加了对 $rootScope 的依赖,在 jQuery AJAX 请求的成功处理程序中,我向 $rootScope 添加了对 $apply 的调用。而已。 :)

app.service('ProductService', ['$http', '$rootScope', function ($http, $rootScope) {
// ...     
// all this stuff stayed the same 
// ...

    //
    // calls web service to add a new product
    self.addNewProduct = function () {

        var formData = new FormData();
        formData.append('ProductName', self.form.productName);

        $.ajax({
            type: "POST",
            url: "/API/ProductAPI/AddUserProduct/36d43a01-22e5-494d-9e46-2d4ea5df7001",
            data: formData,
            processData: false,
            contentType: false
        })
            .done(function (data) {

                if (data != null) {
                    self.products.push(data);
                    self.Title = "Completed";
                    $rootScope.$apply();   // <-- Here's the fix ... 
                }
            });
    };
}]);

【问题讨论】:

标签: javascript angularjs promise angularjs-service angular-promise


【解决方案1】:

由于您使用的是 jQuery 而不是 $http,因此您需要在对要触发更新的手表进行更改后触发 $digest,在您的 .done 函数调用 $scope.$apply();

任何时候你做了一些更新数据但正在异步完成的事情和/或在角度调用的上下文之外,你需要调用 $apply 来触发手表更新(任何不在由 ng-click 调用的函数中或使用 $http 或 $timeout 的东西,因为这些都为您调用 $apply)。

【讨论】:

  • 做到了!我已经添加了修复 OP 的详细信息。谢谢楼主!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-05
  • 1970-01-01
  • 2015-12-07
  • 1970-01-01
  • 2016-09-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多