javascript - AngularJS : Shared Service property not bound to controllers

标签 javascript angularjs promise angularjs-service angular-promise

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

我正在尝试做一些我认为相当简单的事情,在遵循几个教程和 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>

表单和列表由单独的 Controller 管理...每个 Controller 都引用 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 元素绑定(bind)到 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 的不同实例 到每个 Controller 。我已经消除了这种可能性,因为我可以在一个 Controller 中更改属性 svc.Title 并看到它是 传播到另一个 Controller (“咖啡”更改为“茶”)。

无论如何......看来我不知何故失去了对“ self ”的提及。添加新产品的 AJAX 请求完成时的属性,我不确定为什么会这样。我欢迎任何想法或指导。

谢谢, -G

<强>!!解决方案!!

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

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 ... 
                }
            });
    };
}]);

最佳答案

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

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

关于javascript - AngularJS : Shared Service property not bound to controllers,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26366348/

相关文章:

javascript - 如何将 html 转换为 draftjs?

javascript - Fabric.JS 和 AngularJS – 0 和 '0' 之间的区别

javascript - 使用 Angular 指令加载部分不在第二次加载 View 时呈现

javascript - 关于 Javascript 中的异步和 Promise

javascript - 尝试使用 JavaScript 访问由 <use> 生成的 SVG 元素

javascript - Tone.PitchShift 和 Howler.js 问题

javascript - 通过 $sce 服务使用 ngModel 绑定(bind)输入字段

javascript - 如何让 JavaScript 回调等待另一个回调?

node.js - 在做其他事情之前,如何等待循环中的 promise 完成?

javascript - 在 Javascript 中将字符串转换为变量