AngularJS:未绑定到控制器的共享服务属性

时间:2014-10-14 17:07:35

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

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

我正在尝试做一些我认为相当简单的事情,并且在完成了几个教程和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元素绑定到 ProductService 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 
                }
            });
    };
}]);

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

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

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

无论如何......似乎我在某种程度上失去了对“自我”的引用。添加新产品的AJAX请求完成时的属性,我不知道为什么会这样。我欢迎任何想法或指导。

谢谢, -G

!!解决方案!!

感谢 shaunhusain 的解决方案......实际上非常简单的分辨率。我在服务上添加了对$ rootScope的依赖,在jQuery AJAX请求的成功处理程序中,我添加了对$ applyScope的$ 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 ... 
                }
            });
    };
}]);

1 个答案:

答案 0 :(得分:1)

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

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