2013-01-25 49 views
19

Tôi đang cố gắng tìm ra cách bạn xử lý ràng buộc đúng cách khi dữ liệu của tôi được lưu trữ trong một dịch vụ.Xử lý ràng buộc dữ liệu trong AngularJS Services

Tôi có thể làm mọi thứ hoạt động nếu nó đưa dịch vụ vào phạm vi $ và sau đó lấy các mẫu để liên kết trực tiếp với nó nhưng điều đó có vẻ như là một ý tưởng tồi.

Về cơ bản tôi muốn có nó để chế độ xem/bộ điều khiển của tôi có thể dễ dàng thay đổi trạng thái trong dịch vụ và phản ánh ở mọi nơi.

Có vẻ như tôi có thể làm một việc như sau, nhưng nó không hoạt động (http://jsfiddle.net/aidankane/AtRVD/1/).

HTML

<div ng-controller="MyCtl"> 
    <select ng-model="drawing" ng-options="d.file for d in drawings"></select> 
</div> 
<div ng-controller="MyOtherCtl"> 
    {{ drawing }} 
</div> 

JS

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

myApp.factory('myService', function(){ 
    var me = { 
     drawings: [{'file':'a'}, {'file':'b'}] 
    }; 
    // selected drawing 
    me.drawing = me.drawings[0]; 
    return me; 
}); 

function MyCtl($scope, myService){ 
    // can do: 
    // $scope.mys = myService; 
    // and then in html ng-model="mys.drawing" 
    // but that seems wrong 

    $scope.drawings = myService.drawings; 
    $scope.drawing = myService.drawing; 

    // can I not do this? it doesn't seem to work anyway... 
    $scope.$watch('drawing', function(drawing){ 
     myService.drawing = drawing; 
    }); 
} 

function MyOtherCtl($scope, myService){ 
    $scope.drawing = myService.drawing; 
} 

MyCtl.$inject = ['$scope', 'myService']; 
MyOtherCtl.$inject = ['$scope', 'myService']; 
+0

Tôi thấy nơi bạn đang xem $ scope.drawing để thay đổi, nhưng bạn không thay đổi mô hình, bạn sẽ thay đổi mục đã chọn. Bạn không nên đặt trong một xử lý cho sự thay đổi mục đã chọn, có thể trong một chỉ thị? –

+0

Tôi sẽ làm điều này bằng cách sử dụng các chỉ thị như thế nào? Tôi đã tìm ra lệnh ngSelect về cơ bản mang lại cho tôi hành vi mà tôi cần. Sự hiểu biết của tôi về vấn đề này là sự chuyển động giữa bộ điều khiển và dịch vụ đó là vấn đề - sau đó tôi lại hơi bối rối ngay bây giờ :) –

+0

Bạn nói đúng, bây giờ tôi thấy câu chuyện được cập nhật của bạn, tôi có một ý tưởng hay hơn về những gì bạn đang cố gắng. Bạn không bị nhầm lẫn :) –

Trả lời

41

Bạn có thể liên kết với các dịch vụ sử dụng $watch và đi qua một chức năng:

$scope.$watch(function() { return myService.drawing; }, function (drawing) { 
    // handle it here. e.g.: 
    $scope.drawing = drawing; 
}); 

Và sau đó sử dụng $scope.drawing trong các mẫu của bạn và họ sẽ tự động cập nhật:

<div ng-controller="MyOtherCtl"> 
    {{ drawing }} 
</div> 
+1

Ok. Điều đó đặt tôi vào con đường bên phải, tôi nghĩ vậy. Vì vậy, tôi đã tạo một phiên bản mới - http://jsfiddle.net/aidankane/EBr53/ - và tôi đã tạo người theo dõi theo cả hai hướng để đẩy/kéo giữa dịch vụ. Đó có phải là cách làm đúng không? –

+0

@AidanKane Yep! Giao tiếp giữa các thành phần là một câu hỏi phổ biến ở đây và trên danh sách gửi thư. Các dịch vụ là giải pháp phổ biến nhất (và thường là "đúng"). –

+0

Tôi thấy khá sớm rằng họ là đúng cách để giữ dữ liệu. Chỉ cần đấu tranh một chút với sự phối hợp giữa dịch vụ/bộ điều khiển/xem. Có vẻ như bằng cách sử dụng dịch vụ tôi phải đặt một chút boilerplate trong bộ điều khiển để đồng bộ hóa mọi thứ (có quá ít trong bộ điều khiển mà tôi không nhớ). Cảm ơn bạn đã trả lời nhanh chóng, được đánh giá cao. –

2

Tôi nghĩ, thậm chí còn thanh lịch hơn là làm việc với lời hứa (xem $q.deferred()) và giải quyết chúng không đồng bộ. Trong hàm lời hứa, bạn có thể gán dữ liệu cho các thành viên của $scope.

+0

Tốt thôi nếu bạn chỉ tải dữ liệu của mình một lần, nhưng tôi không nghĩ rằng dữ liệu đang thay đổi sẽ tự động liên kết theo cách OP đang tìm kiếm. Có thể sai. –

2

Có hai cách để liên kết dữ liệu từ một dịch vụ: 1) Theo giá trị (sẽ yêu cầu người theo dõi được thực hiện ở trên để kiểm tra thay đổi giá trị dịch vụ nguyên thủy) 2) Theo tham chiếu (giá trị được liên kết trực tiếp) là phương pháp gắn kết dữ liệu ưa thích của tôi.

Tôi sẽ chỉ giải thích khả năng thứ hai kể từ khi câu trả lời được chấp nhận đã cho thấy cách người xem có thể được triển khai. This blog describes what I am going to explain very well.

I created this plunk to illustrate data binding by reference.

Đây là mã từ liệng:

HTML

<!DOCTYPE html> 
<html ng-app="myApp"> 

    <head> 
    <script data-require="[email protected]" data-semver="1.5.0" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script> 
    <link rel="stylesheet" href="style.css" /> 
    <script src="script.js"></script> 
    </head> 

    <body ng-controller="myAppCntrl"> 
    <h1>Hello Plunker!</h1> 
    <h3>By value</h3> 
    <p>{{byValue}}</p> 
    <p>{{objByValue}}</p> 
    <h3>By object in service reference</h3> 
    <p>{{byRefence.stringPrimitive}}</p> 
    <h3>By reference to service singleton</h3> 
    <p>{{myservice.stringPrimitive}}</p> 
    <p style="color: green">of course, you can reference an object through the service as well</p> 
    <p>{{myservice.objectWithPrimitive.stringPrimitive}}</p> 

    <button ng-click=update()>Update strings on service</button> 
    <br /> 
    <button ng-click=setDefaults()>Restore Defaults</button> 
    </body> 

</html> 

JAVASCRIPT

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

myApp.controller('myAppCntrl', function($scope, myAppService){ 
    $scope.myservice = myAppService; 
    $scope.byValue = myAppService.stringPrimitive; 
    $scope.objByValue = myAppService.objectWithPrimitive.stringPrimitive; 
    $scope.byRefence = myAppService.objectWithPrimitive; 

    $scope.update = function() { 
    myAppService.stringPrimitive = "updated string"; 
    myAppService.objectWithPrimitive.stringPrimitive = "updated string here too"; 
    }; 
    $scope.setDefaults = function() { 
    myAppService.stringPrimitive = 'string primitive'; 
    myAppService.objectWithPrimitive.stringPrimitive = 'string primitive'; 
    }; 
}); 

myApp.service('myAppService', function(){ 
    this.stringPrimitive = 'string primitive'; 
    this.objectWithPrimitive = { 
    stringPrimitive: 'string primitive' 
    }; 
}); 

Vậy làm thế nào để làm việc này?

Điều quan trọng là phải hiểu rằng điều này ít liên quan đến cách hoạt động của góc cạnh và rất nhiều việc phải làm với cách hoạt động của Javascript. Khi biến được đặt bằng giá trị nguyên thủy (hoặc được chuyển đến hàm) trong javascript (số nguyên, chuỗi, v.v.) var được đặt theo giá trị. Điều này có nghĩa là biến mới là bản sao của biến bạn đang thiết lập bằng với vị trí mới trong bộ nhớ. Khi một biến được đặt bằng một đối tượng (hoặc được chuyển đến một hàm) trong javascript var được đặt theo tham chiếu.

Điều này có nghĩa là gì?

Khi biến $ scope được đặt theo giá trị và biến dịch vụ thay đổi, vì biến $ scope chỉ là bản sao của biến dịch vụ, biến dịch vụ không còn liên quan gì đến biến dịch vụ và sẽ không thay đổi khi dịch vụ var thực hiện.

Khi giá trị phạm vi $ var được đặt bằng và đối tượng, nó được gán theo Tham chiếu. Điều này có nghĩa là khi đối tượng dịch vụ (lưu ý rằng dịch vụ là một đối tượng vì nó được khởi tạo với từ khóa mới và bạn có thể tham chiếu đến đối tượng đó bằng "this" bên trong dịch vụ) hoặc bất kỳ đối tượng nào trên dịch vụ được tham chiếu được thay đổi, bất kỳ biến $ scope nào tham chiếu đến các đối tượng đó cũng sẽ cập nhật.

Các vấn đề liên quan