AngularJS: পরিষেবা ভেরিয়েবলগুলি কীভাবে দেখবেন?


414

আমার একটি পরিষেবা আছে, বলুন:

factory('aService', ['$rootScope', '$resource', function ($rootScope, $resource) {
  var service = {
    foo: []
  };

  return service;
}]);

এবং আমি fooএইচটিএমএলে রেন্ডার করা একটি তালিকা নিয়ন্ত্রণ করতে ব্যবহার করতে চাই :

<div ng-controller="FooCtrl">
  <div ng-repeat="item in foo">{{ item }}</div>
</div>

কন্ট্রোলার কখন aService.fooআপডেট হয় তা সনাক্ত করার জন্য আমি এই প্যাটার্নটিতে একসাথে আবদ্ধ হয়েছি যেখানে আমি কন্ট্রোলারে একটি পরিষেবা যুক্ত করি $scopeএবং তারপরে ব্যবহার করুন $scope.$watch():

function FooCtrl($scope, aService) {                                                                                                                              
  $scope.aService = aService;
  $scope.foo = aService.foo;

  $scope.$watch('aService.foo', function (newVal, oldVal, scope) {
    if(newVal) { 
      scope.foo = newVal;
    }
  });
}

এটি দীর্ঘমেয়াদী অনুভব করে এবং আমি পরিষেবাটির ভেরিয়েবলগুলি ব্যবহার করে এমন প্রতিটি নিয়ামকটিতে এটি পুনরাবৃত্তি করে চলেছি। ভাগ করা ভেরিয়েবলগুলি দেখার জন্য কী আরও ভাল উপায় আছে?


1
আপনি watch ওয়াচ সেট থেকে গভীর ওয়াচ এ্যাসওয়ার এবং তার সমস্ত বৈশিষ্ট্যগুলির সত্য থেকে সত্য সেট করে তৃতীয় প্যারামিটারটি পাস করতে পারেন।
স্যারটোফামহ্যাট

7
$ সুযোগ.ফু = aService.foo যথেষ্ট, আপনি উপরের লাইনটি হারাতে পারেন। এবং এটি does ঘড়ির ভিতরে কী করে তা বোঝায় না, যদি আপনি $ স্কোপ.ফুতে একটি নতুন মান নির্ধারণ করতে চান তবে এটি করুন ...
জিন

4
আপনি কি aService.fooএইচটিএমএল মার্কআপে উল্লেখ করতে পারেন ? ( এটির মতো: plnkr.co/edit/aNrw5Wo4Q0IxR2loipl5?p=preview )
থেটলওয়েজ

1
আমি কলব্যাকস বা ches ঘড়ি ব্যতীত একটি উদাহরণ যুক্ত করেছি, নীচের উত্তরটি দেখুন ( jsfiddle.net/zymotik/853wvv7s )
জিমোটিক

1
@ মাইকগ্লেডহিল, আপনি ঠিক বলেছেন আমি মনে করি এটি জাভাস্ক্রিপ্টের প্রকৃতির কারণে, আপনি অন্য অনেক জায়গায় এই প্যাটার্নটি দেখতে পারেন (কেবল কৌণিকরাই নয়, জেএসে সাধারণত বলছেন)। একদিকে আপনি মানটি স্থানান্তর করেন (এবং এটি আবদ্ধ হয় না) এবং অন্যদিকে আপনি কোনও বস্তু স্থানান্তর করেন (বা মান যা বস্তুর উল্লেখ করে ...), এবং সে কারণেই বৈশিষ্ট্যগুলি সঠিকভাবে আপডেট করা হয়েছে (পুরোপুরি মতো) উপরের জিমোটিকের উদাহরণে দেখানো হয়েছে)।
ক্রিস্টোফ ভিদাল

উত্তর:


277

আপনি যদি অত্যাচার এবং ওভারহেড এড়াতে চান তবে আপনি সর্বদা ভাল পুরানো পর্যবেক্ষক প্যাটার্নটি ব্যবহার করতে পারেন $watch

সেবায়:

factory('aService', function() {
  var observerCallbacks = [];

  //register an observer
  this.registerObserverCallback = function(callback){
    observerCallbacks.push(callback);
  };

  //call this when you know 'foo' has been changed
  var notifyObservers = function(){
    angular.forEach(observerCallbacks, function(callback){
      callback();
    });
  };

  //example of when you may want to notify observers
  this.foo = someNgResource.query().$then(function(){
    notifyObservers();
  });
});

এবং নিয়ামক মধ্যে:

function FooCtrl($scope, aService){
  var updateFoo = function(){
    $scope.foo = aService.foo;
  };

  aService.registerObserverCallback(updateFoo);
  //service now in control of updating foo
};

21
@ মুমু $destoryইভেন্টটি সুযোগের জন্য শুনুন এবং এতে একটি নিবন্ধভুক্ত পদ্ধতি যুক্ত করুনaService
জেমি

13
এই সমাধানের কি কি? এটিতে একটি পরিষেবাতে আরও কোডের প্রয়োজন হয়, এবং একটি নিয়ামকটিতে কিছুটা সমান কোডের প্রয়োজন (যেহেতু আমাদেরও $ নষ্টের উপরে নিবন্ধন করতে হবে)। আমি মৃত্যুদন্ড কার্যকর করার গতি বলতে পারি, তবে বেশিরভাগ ক্ষেত্রে এটি কোনও বিষয় নয়।
অ্যালেক্স চে

6
$ ঘড়ির চেয়ে কীভাবে এটি আরও ভাল সমাধান তা নিশ্চিত নন, প্রশ্নকারী ডেটা ভাগ করে নেওয়ার একটি সহজ উপায়ের জন্য জিজ্ঞাসা করছিল, এটি আরও জটিল দেখাচ্ছে looks আমি বরং এর চেয়ে সম্প্রচারটি ব্যবহার করব
জিন

11
$watchবনাম পর্যবেক্ষক প্যাটার্নটি কেবল পোলিং করতে হবে বা ধাক্কা দেওয়া উচিত তা বেছে নিচ্ছে এবং মূলত পারফরম্যান্সের বিষয়, তাই পারফরম্যান্সের বিষয়টি গুরুত্বপূর্ণ হলে এটি ব্যবহার করুন। আমি পর্যবেক্ষক প্যাটার্নটি ব্যবহার করি যখন অন্যথায় আমাকে জটিল বস্তুগুলি "গভীর" করতে হবে। আমি একক পরিষেবার মান দেখার পরিবর্তে পুরো পরিষেবাগুলিকে $ সুযোগের সাথে সংযুক্ত করি। আমি কৌণিকের $ শয়তানের মতো ঘড়ির বিষয়টি এড়িয়ে চলি, এটি যথেষ্ট পরিমাণে নির্দেশনা এবং নেটিভ কৌণিক ডেটা-বাইন্ডিংয়ে ঘটছে।
dtheodor

107
কেন আমরা কৌণিকের মতো কাঠামো ব্যবহার করছি তা হ'ল আমাদের নিজস্ব পর্যবেক্ষক নিদর্শনগুলি রান্না করা নয়।
কোড হুইস্পেরার

230

এর মতো দৃশ্যে, যেখানে একাধিক / অজানা অবজেক্টগুলি পরিবর্তনে আগ্রহী হতে পারে, সেখানে $rootScope.$broadcastপরিবর্তিত হওয়া আইটেমটি থেকে ব্যবহার করুন ।

শ্রোতাদের নিজস্ব রেজিস্ট্রি তৈরি করার পরিবর্তে (যা বিভিন্ন ধরণের উপর মুছে ফেলতে হবে) আপনি প্রশ্নযুক্ত $broadcastপরিষেবা থেকে সক্ষম হবেন ।

আপনাকে অবশ্যই $onপ্রতিটি শ্রোতার মধ্যে হ্যান্ডলারের কোড করতে হবে তবে প্যাটার্নটি একাধিক কল থেকে ডিকপল করা হয়েছে $digestএবং এভাবে দীর্ঘ-চলমান পর্যবেক্ষকদের ঝুঁকি এড়ানো হবে।

এইভাবে, শ্রোতাগুলি DOM এবং / অথবা বিভিন্ন শিশু স্কোপ থেকে পরিষেবাটির আচরণ পরিবর্তন না করেই আসতে এবং যেতে পারে।

** আপডেট: উদাহরণসমূহ **

ব্রডকাস্টগুলি "গ্লোবাল" পরিষেবাগুলিতে সর্বাধিক জ্ঞান তৈরি করবে যা আপনার অ্যাপ্লিকেশনটিতে অগণিত অন্যান্য জিনিসগুলিকে প্রভাবিত করতে পারে। একটি ভাল উদাহরণ একটি ব্যবহারকারী পরিষেবা যেখানে লগইন, লগআউট, আপডেট, নিষ্ক্রিয় ইত্যাদির মতো বেশ কয়েকটি ইভেন্ট সংঘটিত হতে পারে I আমি বিশ্বাস করি এখানেই সম্প্রচারগুলি সবচেয়ে সার্থক করে তোলে কারণ কোনও সুযোগ ছাড়াই কোনও ইভেন্ট শুনতে পারে can এমনকি পরিষেবাটি ইনজেকশন দেওয়া হলেও পরিবর্তনের জন্য পরিদর্শন করার জন্য এটির কোনও অভিব্যক্তি বা ক্যাশে ফলাফলগুলি মূল্যায়নের প্রয়োজন হয় না। এটি কেবল আগুন জ্বলে ও ভুলে যায় (সুতরাং এটি নিশ্চিত করুন যে এটি আগুনের-ভুলে যাওয়া বিজ্ঞপ্তি নয়, এমন কোনও পদক্ষেপ নেই যা পদক্ষেপের প্রয়োজন)

.factory('UserService', [ '$rootScope', function($rootScope) {
   var service = <whatever you do for the object>

   service.save = function(data) {
     .. validate data and update model ..
     // notify listeners and provide the data that changed [optional]
     $rootScope.$broadcast('user:updated',data);
   }

   // alternatively, create a callback function and $broadcast from there if making an ajax call

   return service;
}]);

উপরের পরিষেবাটি সেভ () ফাংশনটি শেষ হয়ে গেলে এবং ডেটা বৈধ হয়ে গেলে প্রতিটি স্কোপে একটি বার্তা সম্প্রচার করে। বিকল্পভাবে, যদি এটি কোনও $ রিসোর্স বা এজাক্স জমা দেওয়া হয় তবে ব্রডকাস্ট কলটি কলব্যাকে সরিয়ে ফেলুন যাতে সার্ভারের প্রতিক্রিয়া জানালে এটি আগুনে ছড়িয়ে যায়। সম্প্রচারগুলি সেই প্যাটার্নটি বিশেষত ভাল মানায় কারণ প্রতিটি শ্রোতা কেবল প্রতিটি একক-ডাইজেস্টের সুযোগ পরিদর্শন করার প্রয়োজন ছাড়াই ইভেন্টটির জন্য অপেক্ষা করে। শ্রোতাদের মত লাগবে:

.controller('UserCtrl', [ 'UserService', '$scope', function(UserService, $scope) {

  var user = UserService.getUser();

  // if you don't want to expose the actual object in your scope you could expose just the values, or derive a value for your purposes
   $scope.name = user.firstname + ' ' +user.lastname;

   $scope.$on('user:updated', function(event,data) {
     // you could inspect the data to see if what you care about changed, or just update your own scope
     $scope.name = user.firstname + ' ' + user.lastname;
   });

   // different event names let you group your code and logic by what happened
   $scope.$on('user:logout', function(event,data) {
     .. do something differently entirely ..
   });

 }]);

এর অন্যতম সুবিধা হ'ল একাধিক ঘড়ি বাদ দেওয়া। আপনি যদি ক্ষেত্রের সংমিশ্রণ বা উপরের উদাহরণের মতো মানগুলি অর্জন করছিলেন তবে আপনাকে প্রথম নাম এবং পদবি দুটি বৈশিষ্ট্যই দেখতে হবে। গেট ইউজার () ফাংশনটি দেখা কেবল তখনই কাজ করবে যদি ব্যবহারকারীর অবজেক্টটি আপডেটের পরিবর্তে প্রতিস্থাপন করা হয়, যদি ব্যবহারকারী অবজেক্টটি কেবল তার বৈশিষ্ট্যগুলি আপডেট করে থাকে তবে তা আগুন দেয় না। এক্ষেত্রে আপনাকে গভীর নজর রাখতে হবে এবং এটি আরও নিবিড়।

$ সম্প্রচারটি কোনও চাইল্ড স্কোপে ডেকে পাঠানোর সুযোগ থেকে বার্তা প্রেরণ করে। সুতরাং এটিকে $ রুটস্কোপ থেকে কল করা প্রতিটি সুযোগে আগুন ছড়িয়ে দেবে। আপনি যদি আপনার নিয়ন্ত্রকের স্কোপ থেকে $ সম্প্রচার করতে চান, উদাহরণস্বরূপ, এটি কেবল আপনার নিয়ামকের সুযোগ থেকে উত্তরাধিকার সূত্রেই আগুন লাগবে। mit প্রসারণ বিপরীত দিকে যায় এবং এটি কোনও স্কোপ চেইনকে বুদ্বুদ দেয় এমন কোনও ডিওএম ইভেন্টের সাথে একই রকম আচরণ করে।

মনে রাখবেন এমন কিছু পরিস্থিতিতে রয়েছে যেখানে $ সম্প্রচারটি প্রচুর পরিমাণে অর্থবোধ করে এবং এমন দৃশ্যও রয়েছে যেখানে $ ঘড়িটি আরও ভাল বিকল্প - বিশেষত যদি খুব নির্দিষ্ট ঘড়ির মত প্রকাশের সাথে একটি বিচ্ছিন্ন সুযোগে থাকে।


1
Gest ডাইজেস্ট চক্র থেকে বেরিয়ে আসা ভাল জিনিস, বিশেষত যদি আপনি যে পরিবর্তনগুলি দেখছেন সেটি কোনও মান না হয় যা সরাসরি এবং তাত্ক্ষণিকভাবে ডমের মধ্যে চলে যায়।
এক্সএমএল

.Save () পদ্ধতি এড়াতে কি দূরে আছে? ওভারকিলের মতো মনে হয় যখন আপনি কেবল শেয়ারড সার্ভিসে কোনও একক ভেরিয়েবলের আপডেট পর্যবেক্ষণ করছেন। আমরা ভাগ করে নেওয়া পরিষেবাগুলির মধ্যে থেকে পরিবর্তনশীলটি দেখতে পারি এবং এটি পরিবর্তিত হলে সম্প্রচারিত করতে পারি?
জেরিকুর

আমি নিয়ন্ত্রকদের মধ্যে ডেটা ভাগ করে নেওয়ার জন্য বেশ কয়েকটি উপায় চেষ্টা করেছি, তবে এটিই কেবল কাজ করে। ভাল খেলেছে স্যার।
অ্যাবেটারম্যাপ

আমি পছন্দ এই অন্য উত্তর, কম বলে মনে হয় হল hacky , ধন্যবাদ
JMK

9
এটি কেবলমাত্র সঠিক ডিজাইনের প্যাটার্ন যদি আপনার গ্রাহক নিয়ামকের কাছে ডেটার একাধিক সম্ভাব্য উত্স থাকে; অন্য কথায়, আপনার যদি মিমো পরিস্থিতি থাকে (একাধিক ইনপুট / একাধিক আউটপুট)। আপনি যদি কেবলমাত্র এক থেকে একাধিক প্যাটার্ন ব্যবহার করছেন তবে আপনার সরাসরি অবজেক্ট রেফারেন্সিং ব্যবহার করা উচিত এবং কৌণিক কাঠামোটি আপনার জন্য দ্বি-মুখী আবদ্ধ হতে দেওয়া উচিত। হারকিজে এটি নীচে লিঙ্ক করেছেন এবং এটি স্বয়ংক্রিয় দ্বি-মুখী বাঁধাইয়ের একটি ভাল ব্যাখ্যা, এবং এটির সীমাবদ্ধতা: stsc3000.github.io/blog/2013/10/26/…
চার্লস

47

আমি @ ডিটিওডোট হিসাবে একই রকম ব্যবহার করছি তবে কলব্যাকগুলি পাস করার পরিবর্তে কৌনিক প্রতিশ্রুতি ব্যবহার করছি

app.service('myService', function($q) {
    var self = this,
        defer = $q.defer();

    this.foo = 0;

    this.observeFoo = function() {
        return defer.promise;
    }

    this.setFoo = function(foo) {
        self.foo = foo;
        defer.notify(self.foo);
    }
})

তারপরে যেখানেই কেবল পরিষেবাটিতে myService.setFoo(foo)আপডেট করার জন্য পদ্ধতি ব্যবহার fooকরুন। আপনার নিয়ামক হিসাবে আপনি এটি ব্যবহার করতে পারেন:

myService.observeFoo().then(null, null, function(foo){
    $scope.foo = foo;
})

প্রথম দুটি যুক্তি thenহ'ল সাফল্য এবং ত্রুটি কলব্যাকস, তৃতীয়টি কলব্যাকটি অবহিত।

$ কিউ জন্য রেফারেন্স।


এই পদ্ধতির সুবিধা কী হবে Matt সম্প্রচারিত ম্যাট পাইলেগির দ্বারা বর্ণিত বেলো?
ফ্যাবিও

ভাল উভয় পদ্ধতি তাদের ব্যবহার আছে। আমার জন্য সম্প্রচারের সুবিধা হ'ল মানব পাঠযোগ্যতা এবং একই ইভেন্টে আরও জায়গাগুলিতে শোনার সম্ভাবনা। আমি অনুমান করি যে প্রধান অসুবিধাটি হ'ল সম্প্রচারটি সমস্ত বংশধরদের জন্য বার্তা প্রেরণ করছে যাতে এটি কোনও পারফরম্যান্স সমস্যা হতে পারে।
ক্রাইম

2
$scope.$watchসার্ভিস ভেরিয়েবলের কাজ করা মনে হচ্ছে না এমন সমস্যা আমার ছিল (আমি যে স্কোপটিতে দেখছিলাম তা একটি মডেল যা উত্তরাধিকার সূত্রে প্রাপ্ত হয়েছিল $rootScope) - এটি কাজ করে। দুর্দান্ত কৌশল, ভাগ করে নেওয়ার জন্য ধন্যবাদ!
সিয়েরিয়া

4
আপনি এই পদ্ধতির সাহায্যে নিজের পরে কীভাবে পরিষ্কার করবেন? সুযোগটি নষ্ট হয়ে গেলে কি প্রতিশ্রুতি থেকে নিবন্ধিত কলব্যাক সরিয়ে ফেলা সম্ভব?
আব্রিস

ভাল প্রশ্ন. আমি সত্যই জানি না। আপনি কীভাবে প্রতিশ্রুতি থেকে কলবিব্যাক কলটি সরিয়ে ফেলতে পারেন তার কয়েকটি পরীক্ষা করার চেষ্টা করব।
ক্রাইম

41

ঘড়ি বা পর্যবেক্ষক কলব্যাক ব্যতীত ( http://jsfiddle.net/zymotik/853wvv7s/ ):

javascript:

angular.module("Demo", [])
    .factory("DemoService", function($timeout) {

        function DemoService() {
            var self = this;
            self.name = "Demo Service";

            self.count = 0;

            self.counter = function(){
                self.count++;
                $timeout(self.counter, 1000);
            }

            self.addOneHundred = function(){
                self.count+=100;
            }

            self.counter();
        }

        return new DemoService();

    })
    .controller("DemoController", function($scope, DemoService) {

        $scope.service = DemoService;

        $scope.minusOneHundred = function() {
            DemoService.count -= 100;
        }

    });

এইচটিএমএল

<div ng-app="Demo" ng-controller="DemoController">
    <div>
        <h4>{{service.name}}</h4>
        <p>Count: {{service.count}}</p>
    </div>
</div>

এই জাভাস্ক্রিপ্টটি যখন আমরা কোনও মান বাদ দিয়ে পরিষেবা থেকে পিছনে চলে যাচ্ছি তখন কাজ করে। যখন কোনও জাভাস্ক্রিপ্ট অবজেক্ট কোনও পরিষেবা থেকে ফিরে আসে তখন কৌণিকর তার সমস্ত বৈশিষ্ট্যে ঘড়ি যুক্ত করে।

এছাড়াও নোট করুন যে আমি 'var স্ব = এটি' ব্যবহার করছি কারণ যখন $ সময়সীমা নির্বাহ করা হয় তখন মূল বস্তুর সাথে আমার একটি রেফারেন্স রাখা প্রয়োজন, অন্যথায় 'এটি' উইন্ডো অবজেক্টটি উল্লেখ করবে।


3
এটি একটি দুর্দান্ত পদ্ধতির! পুরো পরিষেবাটির পরিবর্তে কোনও পরিষেবার কোনও সম্পত্তিকে সুযোগের সাথে বেঁধে রাখার কী উপায় আছে? স্রেফ করা কাজ $scope.count = service.countকরে না।
jvannistelrooy

আপনি কোনও (স্বেচ্ছাসেবী) কোনও বস্তুর অভ্যন্তরের সম্পত্তিটিও বাসা বেঁধে ফেলতে পারেন যাতে এটি রেফারেন্সের মধ্য দিয়ে যায়। $scope.data = service.data <p>Count: {{ data.count }}</p>
অ্যালেক্স রস

1
দুর্দান্ত পদ্ধতির! এই পৃষ্ঠায় প্রচুর শক্তিশালী, কার্যকরী উত্তর থাকা সত্ত্বেও এটি এখন পর্যন্ত ক) বাস্তবায়ন করা সবচেয়ে সহজ এবং খ) কোডটি পড়ার সময় বোঝা সহজ। এই উত্তরটি বর্তমানে তুলনায় অনেক বেশি হওয়া উচিত।
কোডমুজ

ধন্যবাদ @ কোডমূস, অ্যাঙ্গুলারজেএস / জাভাস্ক্রিপ্টে নতুন যারা এসেছেন তাদের জন্য আমি আজও এটিকে আরও সহজ করেছি।
জিমোটিক

2
আল্লাহ তোমার মঙ্গল করুক. আমি বলতে চাই মিলিয়ন ঘন্টা মত নষ্ট করেছি। কারণ আমি 1.5 এবং আঙ্গুলের সাথে লড়াই করে 1 থেকে 2 এ স্থান পরিবর্তন করেছি এবং ডেটাও ভাগ করে নিতে চেয়েছিলাম
আমনা

29

আমি এই জাতীয় অনুরূপ কিছু সন্ধানে এই প্রশ্নে হোঁচট খেয়েছি, তবে আমি মনে করি এটি কী ঘটছে তার পাশাপাশি তার অতিরিক্ত কিছু সমাধানের একটি বিশদ ব্যাখ্যার প্রাপ্য।

যখন একটি কৌণিক অভিব্যক্তি এক আপনি ব্যবহার HTML এ উপস্থিত যেমন কৌণিক স্বয়ংক্রিয়ভাবে একটি সেট করে $watchজন্য $scope.foo, এবং যখনই এইচটিএমএল আপডেট হবে $scope.fooপরিবর্তন।

<div ng-controller="FooCtrl">
  <div ng-repeat="item in foo">{{ item }}</div>
</div>

এখানে অনির্যুক্ত সমস্যাটি হ'ল দুটি জিনিসের একটির এমনটি প্রভাবিত aService.foo হচ্ছে যাতে পরিবর্তনগুলি সনাক্ত করা যায় না। এই দুটি সম্ভাবনা হ'ল:

  1. aService.foo প্রতিবার একটি নতুন অ্যারেতে সেট হয়ে যাচ্ছে, যার কারণে উল্লেখটি পুরানো হয়ে যায়।
  2. aService.fooএমনভাবে আপডেট করা হচ্ছে $digestযাতে আপডেটে কোনও চক্রটি ট্রিগার না হয়।

সমস্যা 1: পুরানো রেফারেন্স

প্রথম সম্ভাবনা বিবেচনা করে, ধরে $digestনেওয়া হচ্ছে যে প্রয়োগ করা হচ্ছে, যদি aService.fooসর্বদা একই অ্যারে হয় তবে স্বয়ংক্রিয়ভাবে সেটটি $watchনীচের কোড স্নিপেটে দেখানো অনুসারে পরিবর্তনগুলি সনাক্ত করবে।

সমাধান 1-এ: নিশ্চিত হন যে প্রতিটি আপডেটে অ্যারে বা অবজেক্ট একই জিনিস

আপনি দেখতে পাচ্ছেন, অনুমিতভাবে সংযুক্ত এনজি-রিপিট পরিবর্তন aService.fooহওয়ার সাথে সাথে আপডেট হয় না aService.foo, তবে এনজি-রিপিট সংযুক্ত aService2.foo থাকে । এটি কারণ আমাদের রেফারেন্সটি aService.fooপুরানো, তবে আমাদের রেফারেন্সটি aService2.fooতা নয়। আমরা প্রারম্ভিক অ্যারের সাথে একটি রেফারেন্স তৈরি করেছি $scope.foo = aService.foo;, এটি পরবর্তী আপডেটে পরিষেবা দ্বারা বাতিল করা হয়েছিল, যার অর্থ $scope.fooআর আর আমরা চাইছি না এমন অ্যারে রেফারেন্স করা।

যাইহোক, প্রাথমিক রেফারেন্সটি কৌশলে রাখা হয়েছে তা নিশ্চিত করার বেশ কয়েকটি উপায় রয়েছে, তবে কখনও কখনও অবজেক্ট বা অ্যারে পরিবর্তন করা প্রয়োজন। বা যদি পরিষেবার সম্পত্তিটি কোনও Stringবা আধ্যাত্মিক আদিম হিসাবে উল্লেখ করে Number? এই ক্ষেত্রে, আমরা কেবল একটি রেফারেন্সের উপর নির্ভর করতে পারি না। তাহলে আমরা কী করতে পারি?

ইতিমধ্যে দেওয়া বেশ কয়েকটি উত্তর ইতিমধ্যে সেই সমস্যার কিছু সমাধান দেয়। যাইহোক, আমি ব্যক্তিগতভাবে মন্তব্যগুলিতে জিন এবং থেলওয়েজদের পরামর্শ দেওয়া সহজ পদ্ধতিটি ব্যবহারের পক্ষে :

এইচটিএমএল মার্কআপে কেবল aService.foo উল্লেখ করুন

সমাধান 1-বি: পরিষেবাতে সুযোগের সাথে সংযুক্তি করুন, এবং {service}.{property}এইচটিএমএলে রেফারেন্স করুন।

অর্থ, কেবল এটি করুন:

এইচটিএমএল:

<div ng-controller="FooCtrl">
  <div ng-repeat="item in aService.foo">{{ item }}</div>
</div>

জাতীয়:

function FooCtrl($scope, aService) {
    $scope.aService = aService;
}

এইভাবে, প্রতিটির মধ্যে সংকল্পটি $watchসমাধান হবে, যা সঠিকভাবে আপডেট হওয়া মান পাবে।aService.foo$digest

আপনি নিজের কাজের সাথে যা করার চেষ্টা করছেন এটি এটির মতো, তবে উপায়টি প্রায় খুব কম। আপনি $watchনিয়ামকটিতে একটি অপ্রয়োজনীয় যোগ করেছেন যা যখনই পরিবর্তন fooহয় $scopeতখন স্পষ্টতই রাখে । আপনি যে অতিরিক্ত প্রয়োজন হবে না $watchযখন আপনি সংযুক্ত aServiceপরিবর্তে aService.fooকরার $scopeবেঁধে স্পষ্টভাবে, এবং aService.fooমার্কআপ হবে।


এখন এটি বেশ ভাল এবং ধরে নিচ্ছি একটি $digestচক্র প্রয়োগ করা হচ্ছে। উপরের আমার উদাহরণগুলিতে আমি $intervalঅ্যারেগুলি আপডেট করতে অ্যাংুলার পরিষেবা ব্যবহার করেছি , যা $digestপ্রতিটি আপডেটের পরে স্বয়ংক্রিয়ভাবে একটি লুপ বন্ধ করে দেয় off তবে কী যদি পরিষেবা ভেরিয়েবলগুলি (যে কারণেই হোক না কেন) "কৌণিক বিশ্বের" ভিতরে আপডেট হচ্ছে না। অন্য কথায়, যখনই পরিষেবার সম্পত্তি পরিবর্তিত হয় তখন আমরা একটি চক্র স্বয়ংক্রিয়ভাবে সক্রিয় হয়ে উঠব না$digest ?


সমস্যা 2: অনুপস্থিত $digest

এখানকার অনেকগুলি সমাধানই এই সমস্যাটি সমাধান করবে, তবে আমি কোড হুইস্পেরারের সাথে একমত :

কেন আমরা কৌণিকের মতো কাঠামো ব্যবহার করছি তা হ'ল আমাদের নিজস্ব পর্যবেক্ষক নিদর্শনগুলি রান্না করা নয়

অতএব, আমি aService.fooউপরের দ্বিতীয় উদাহরণে যেমন দেখিয়েছি HTML মার্কআপে রেফারেন্সটি ব্যবহার করা চালিয়ে যেতে পছন্দ করব এবং নিয়ামকের মধ্যে কোনও অতিরিক্ত কলব্যাক নিবন্ধন করতে হবে না back

সমাধান 2: এর সাথে একটি সেটার এবং গেটর ব্যবহার করুন $rootScope.$apply()

আমি অবাক হয়েছি এখনও কেউ সেটার এবং গেটর ব্যবহারের পরামর্শ দেয়নি । এই ক্ষমতাটি ECMAScript5 তে প্রবর্তিত হয়েছিল, এবং এটি এখন বছরের পর বছর ধরে রয়েছে। অবশ্যই, এর অর্থ যদি, যে কোনও কারণে, আপনাকে সত্যিকারের পুরানো ব্রাউজারগুলি সমর্থন করা দরকার, তবে এই পদ্ধতিটি কার্যকর হবে না, তবে আমার মনে হয় জাভাস্ক্রিপ্টে গেটারস এবং সেটটারগুলি বিস্তৃতভাবে নিখরচায় রয়েছে। এই বিশেষ ক্ষেত্রে, তারা বেশ কার্যকর হতে পারে:

factory('aService', [
  '$rootScope',
  function($rootScope) {
    var realFoo = [];

    var service = {
      set foo(a) {
        realFoo = a;
        $rootScope.$apply();
      },
      get foo() {
        return realFoo;
      }
    };
  // ...
}

এখানে আমি সেবা ফাংশন একটি 'ব্যক্তিগত' পরিবর্তনশীল যোগ করেছেন: realFoo। এই পেতে আপডেট এবং ব্যবহার উদ্ধার হচ্ছে get foo()এবং set foo()উপর যথাক্রমে ফাংশন serviceঅবজেক্ট।

$rootScope.$apply()সেট ফাংশনটির ব্যবহারটি নোট করুন । এটি নিশ্চিত করে যে কৌনিক কোনও পরিবর্তন সম্পর্কে সচেতন হবে service.foo। আপনি যদি 'ইনগ্রোগ' ত্রুটি পান তবে এই দরকারী রেফারেন্স পৃষ্ঠাটি দেখতে পান বা আপনি কৌনিক > = 1.3 ব্যবহার করেন তবে আপনি কেবল ব্যবহার করতে পারেন $rootScope.$applyAsync()

এছাড়াও aService.fooখুব ঘন ঘন আপডেট করা হয় তবে এটি থেকে সতর্ক থাকুন , যেহেতু এটি পারফরম্যান্সকে উল্লেখযোগ্যভাবে প্রভাবিত করতে পারে। পারফরম্যান্স যদি কোনও সমস্যা হয়ে থাকে তবে আপনি সেটারটি ব্যবহার করে এখানে অন্যান্য উত্তরের মতো একটি পর্যবেক্ষক প্যাটার্ন সেট আপ করতে পারেন।


3
এটি সঠিক এবং সহজ সমাধান। @ ন্যানো উইজার্ড যেমন বলেছে, properties সেবারের মালিকানাধীন servicesবৈশিষ্ট্যগুলির জন্য নয় for
সার্পডোরুক তাহমাজ

28

আমি যতদূর বলতে পারি, আপনাকে এর মতো বিস্তৃত কিছু করতে হবে না। আপনি ইতিমধ্যে পরিষেবা থেকে আপনার সুযোগে foo নিয়োগ করেছেন এবং যেহেতু foo একটি অ্যারে (এবং পরিবর্তে কোনও বিষয় এটি রেফারেন্স দ্বারা নির্ধারিত হয়!)। সুতরাং, আপনাকে যা করতে হবে তা হ'ল কিছু:

function FooCtrl($scope, aService) {                                                                                                                              
  $scope.foo = aService.foo;

 }

যদি কিছু, এই একই সিটিআরএলটির অন্যান্য ভেরিয়েবলগুলি ফু পরিবর্তনের উপর নির্ভর করে তবে হ্যাঁ, আপনার foo পর্যবেক্ষণ এবং সেই পরিবর্তনশীলটিতে পরিবর্তন করার জন্য একটি ঘড়ি প্রয়োজন। তবে যতক্ষণ না এটি একটি সাধারণ রেফারেন্স দেখা অপ্রয়োজনীয়। আশাকরি এটা সাহায্য করবে.


35
আমি চেষ্টা করেছি, এবং আমি $watchকোনও আদিমকে নিয়ে কাজ করতে পারি না । পরিবর্তে, আমি পরিষেবা যা আদিম মান ফিরে আসবে উপর একটি পদ্ধতি সংজ্ঞা দিয়েছে: somePrimitive() = function() { return somePrimitive }আমি যে পদ্ধতি একটি $ সুযোগ সম্পত্তি নিয়োগ: $scope.somePrimitive = aService.somePrimitive;। তারপরে আমি এইচটিএমএলে স্কোপ পদ্ধতিটি ব্যবহার করেছি: <span>{{somePrimitive()}}</span>
রাজকক

4
পুনঃটুইট করেছেন এগুলিকে একটি বস্তুতে যুক্ত করুন। প্রিমিটিভগুলি পরিবর্তনযোগ্য নয় এবং তাই 2 তম ডেটা বাঁধাই কাজ করবে না
জিমি কেন

3
@ জিম্মিਕੇেন, হ্যাঁ, আদিমগুলি 2-উপায় ডেটাবাইন্ডিংয়ের জন্য ব্যবহার করা উচিত নয়, তবে আমি মনে করি যে প্রশ্নটি সার্ভিস ভেরিয়েবলগুলি দেখার বিষয়ে ছিল, 2-উপায় বাইন্ডিং স্থাপন না করে। আপনার যদি কেবল কোনও পরিষেবার সম্পত্তি / পরিবর্তনশীল দেখতে হয় তবে কোনও বস্তুর প্রয়োজন হয় না - একটি আদিম ব্যবহার করা যেতে পারে।
রাজকোক

3
এই সেট আপে আমি সুযোগ থেকে এই সেবা মান পরিবর্তন করতে সক্ষম। তবে পরিষেবাটি পরিবর্তিত হয়ে প্রতিক্রিয়াতে সুযোগটি পরিবর্তন হয় না।
ওউভেন হুয়াং

4
এটিও আমার পক্ষে কাজ করে না। কেবল অ্যাসাইনিংয়ের $scope.foo = aService.fooসাথে স্কোপ ভেরিয়েবলটি স্বয়ংক্রিয়ভাবে আপডেট হয় না।
ডারউইন টেক

9

আপনি পরিষেবাটি $ রুটস্কোপে সন্নিবেশ করতে পারেন এবং দেখুন:

myApp.run(function($rootScope, aService){
    $rootScope.aService = aService;
    $rootScope.$watch('aService', function(){
        alert('Watch');
    }, true);
});

আপনার নিয়ামক মধ্যে:

myApp.controller('main', function($scope){
    $scope.aService.foo = 'change';
});

অন্যান্য বিকল্পটি হ'ল বাহ্যিক গ্রন্থাগার যেমন: https://github.com/melanke/Watch.JS ব্যবহার করা

এর সাথে কাজ করে: আইই 9+, এফএফ 4+, এসএফ 5+, ওয়েবকিট, সিএইচ 7+, অপি 12+, বেসেন, নোড.জেএস, রাইনো 1.7+

আপনি এক বা একাধিক বা সমস্ত বস্তুর বৈশিষ্ট্যের পরিবর্তনগুলি পর্যবেক্ষণ করতে পারেন।

উদাহরণ:

var ex3 = {
    attr1: 0,
    attr2: "initial value of attr2",
    attr3: ["a", 3, null]
};   
watch(ex3, function(){
    alert("some attribute of ex3 changes!");
});
ex3.attr3.push("new value");​

2
আমি এই উত্তরটি বিশ্বাস করতে পারি না সবচেয়ে বেশি ভোট দেওয়া হয় না !!! এটি সর্বাধিক মার্জিত সমাধান (আইএমও) কারণ এটি তথ্য-এনট্রপি হ্রাস করে এবং সম্ভবত অতিরিক্ত মধ্যস্থতা হ্যান্ডলারের প্রয়োজনীয়তা হ্রাস করে। আমি পারলে আরও বেশি ভোট দিতাম ...
কোডি

: সম্ভাব্য ফাঁদ $ rootScope, তার সুবিধা আপনার সব পরিষেবা যোগ করার পদ্ধতি এবং এটি আছে, কিছুটা বিস্তারিত করছে stackoverflow.com/questions/14573023/...
Zymotik

6

আপনি কারখানার মধ্যেই পরিবর্তনগুলি দেখতে পারেন এবং তারপরে একটি পরিবর্তন সম্প্রচার করতে পারেন

angular.module('MyApp').factory('aFactory', function ($rootScope) {
    // Define your factory content
    var result = {
        'key': value
    };

    // add a listener on a key        
    $rootScope.$watch(function () {
        return result.key;
    }, function (newValue, oldValue, scope) {
        // This is called after the key "key" has changed, a good idea is to broadcast a message that key has changed
        $rootScope.$broadcast('aFactory:keyChanged', newValue);
    }, true);

    return result;
});

তারপরে আপনার নিয়ামকটিতে:

angular.module('MyApp').controller('aController', ['$rootScope', function ($rootScope) {

    $rootScope.$on('aFactory:keyChanged', function currentCityChanged(event, value) {
        // do something
    });
}]);

এই পদ্ধতিতে আপনি সম্পর্কিত সমস্ত কারখানার কোডটিকে তার বর্ণনার মধ্যে রেখেছেন তবে আপনি কেবল বাইরে থেকে সম্প্রচারের উপর নির্ভর করতে পারেন


6

== আপডেট ==

ওয়াচ এ এখন খুব সহজ।

কলম এখানে

এইচটিএমএল:

<div class="container" data-ng-app="app">

  <div class="well" data-ng-controller="FooCtrl">
    <p><strong>FooController</strong></p>
    <div class="row">
      <div class="col-sm-6">
        <p><a href="" ng-click="setItems([ { name: 'I am single item' } ])">Send one item</a></p>
        <p><a href="" ng-click="setItems([ { name: 'Item 1 of 2' }, { name: 'Item 2 of 2' } ])">Send two items</a></p>
        <p><a href="" ng-click="setItems([ { name: 'Item 1 of 3' }, { name: 'Item 2 of 3' }, { name: 'Item 3 of 3' } ])">Send three items</a></p>
      </div>
      <div class="col-sm-6">
        <p><a href="" ng-click="setName('Sheldon')">Send name: Sheldon</a></p>
        <p><a href="" ng-click="setName('Leonard')">Send name: Leonard</a></p>
        <p><a href="" ng-click="setName('Penny')">Send name: Penny</a></p>
      </div>
    </div>
  </div>

  <div class="well" data-ng-controller="BarCtrl">
    <p><strong>BarController</strong></p>
    <p ng-if="name">Name is: {{ name }}</p>
    <div ng-repeat="item in items">{{ item.name }}</div>
  </div>

</div>

javascript:

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

app.factory('PostmanService', function() {
  var Postman = {};
  Postman.set = function(key, val) {
    Postman[key] = val;
  };
  Postman.get = function(key) {
    return Postman[key];
  };
  Postman.watch = function($scope, key, onChange) {
    return $scope.$watch(
      // This function returns the value being watched. It is called for each turn of the $digest loop
      function() {
        return Postman.get(key);
      },
      // This is the change listener, called when the value returned from the above function changes
      function(newValue, oldValue) {
        if (newValue !== oldValue) {
          // Only update if the value changed
          $scope[key] = newValue;
          // Run onChange if it is function
          if (angular.isFunction(onChange)) {
            onChange(newValue, oldValue);
          }
        }
      }
    );
  };
  return Postman;
});

app.controller('FooCtrl', ['$scope', 'PostmanService', function($scope, PostmanService) {
  $scope.setItems = function(items) {
    PostmanService.set('items', items);
  };
  $scope.setName = function(name) {
    PostmanService.set('name', name);
  };
}]);

app.controller('BarCtrl', ['$scope', 'PostmanService', function($scope, PostmanService) {
  $scope.items = [];
  $scope.name = '';
  PostmanService.watch($scope, 'items');
  PostmanService.watch($scope, 'name', function(newVal, oldVal) {
    alert('Hi, ' + newVal + '!');
  });
}]);

1
আমি পোস্টম্যান সার্ভিস পছন্দ করি তবে আমার কীভাবে একাধিক পরিবর্তনশীল শোনার প্রয়োজন হলে কন্ট্রোলারে ওয়াচ ফাংশনটি কীভাবে পরিবর্তন করতে হবে?
jedi

হাই জেডি, মাথা আপ জন্য ধন্যবাদ! আমি কলম এবং উত্তর আপডেট করেছি। আমি তার জন্য আরও একটি ঘড়ি ফাংশন যোগ করার জন্য পুনরায় স্বীকার করছি। সুতরাং, আমি পোস্টম্যান সার্ভিসে একটি নতুন বৈশিষ্ট্য যুক্ত করেছি। আমি আশা করি এটি সাহায্য করে :)
হায়াতবিরললেম

আসলে, হ্যাঁ এটি :) আপনি যদি সমস্যাটির আরও বিস্তারিত ভাগ করেন তবে আমি আপনাকে সহায়তা করতে পারি।
হায়াতবীরলেম

4

উপর নির্মাণের dtheodor এর আপনি নীচের অনুরূপ কিছু ব্যবহার করতে পারে তা নিশ্চিত করতে ভুলবেন না যে কলব্যাক নিবন্ধন মুক্ত করুন ... কিছু ক্ষণস্থায়ী আপত্তি পারে উত্তর $scopeযদিও একটি সেবা করতে।

factory('aService', function() {
  var observerCallbacks = [];

  /**
   * Registers a function that will be called when
   * any modifications are made.
   *
   * For convenience the callback is called immediately after registering
   * which can be prevented with `preventImmediate` param.
   *
   * Will also automatically unregister the callback upon scope destory.
   */
  this.registerObserver = function($scope, cb, preventImmediate){
    observerCallbacks.push(cb);

    if (preventImmediate !== true) {
      cb();
    }

    $scope.$on('$destroy', function () {
      observerCallbacks.remove(cb);
    });
  };

  function notifyObservers() {
    observerCallbacks.forEach(function (cb) {
      cb();
    });
  };

  this.foo = someNgResource.query().$then(function(){
    notifyObservers();
  });
});

অ্যারে.রেমভ হ'ল একটি এক্সটেনশন পদ্ধতি যা দেখতে এরকম দেখাচ্ছে:

/**
 * Removes the given item the current array.
 *
 * @param  {Object}  item   The item to remove.
 * @return {Boolean}        True if the item is removed.
 */
Array.prototype.remove = function (item /*, thisp */) {
    var idx = this.indexOf(item);

    if (idx > -1) {
        this.splice(idx, 1);

        return true;
    }
    return false;
};

2

এখানে আমার জেনেরিক পদ্ধতি।

mainApp.service('aService',[function(){
        var self = this;
        var callbacks = {};

        this.foo = '';

        this.watch = function(variable, callback) {
            if (typeof(self[variable]) !== 'undefined') {
                if (!callbacks[variable]) {
                    callbacks[variable] = [];
                }
                callbacks[variable].push(callback);
            }
        }

        this.notifyWatchersOn = function(variable) {
            if (!self[variable]) return;
            if (!callbacks[variable]) return;

            angular.forEach(callbacks[variable], function(callback, key){
                callback(self[variable]);
            });
        }

        this.changeFoo = function(newValue) {
            self.foo = newValue;
            self.notifyWatchersOn('foo');
        }

    }]);

আপনার নিয়ামক মধ্যে

function FooCtrl($scope, aService) {
    $scope.foo;

    $scope._initWatchers = function() {
        aService.watch('foo', $scope._onFooChange);
    }

    $scope._onFooChange = function(newValue) {
        $scope.foo = newValue;
    }

    $scope._initWatchers();

}

FooCtrl.$inject = ['$scope', 'aService'];

2

আমার মতো যারা কেবল একটি সহজ সমাধানের সন্ধান করেন, এটি নিয়ামকগুলিতে সাধারণ $ ঘড়ি ব্যবহার থেকে আপনি যা প্রত্যাশা করেন ঠিক এটিই করে। পার্থক্যটি হ'ল, এটি জাভাস্ক্রিপ্ট প্রসঙ্গে স্ট্রিংটি মূল্যায়ন করে এবং কোনও নির্দিষ্ট সুযোগে নয়। আপনাকে আপনার পরিষেবাতে $ রুটস্কোপ ইনজেকশন দিতে হবে, যদিও এটি কেবল ডাইজেস্ট চক্রগুলিতে সঠিকভাবে হুক করার জন্য ব্যবহৃত হয়।

function watch(target, callback, deep) {
    $rootScope.$watch(function () {return eval(target);}, callback, deep);
};

2

খুব অনুরূপ সমস্যার মুখোমুখি হয়ে আমি স্কোপটিতে একটি ফাংশন দেখেছি এবং ফাংশনটি পরিষেবা ভেরিয়েবলটি ফিরিয়ে আনতে পেরেছিলাম। আমি একটি তৈরি করেছেন JS বেহালার । আপনি নীচের কোড খুঁজে পেতে পারেন।

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

myApp.factory("randomService", function($timeout){
    var retValue = {};
    var data = 0;

    retValue.startService = function(){
        updateData();
    }

    retValue.getData = function(){
        return data;
    }

    function updateData(){
        $timeout(function(){
            data = Math.floor(Math.random() * 100);
            updateData()
        }, 500);
    }

    return retValue;
});

myApp.controller("myController", function($scope, randomService){
    $scope.data = 0;
    $scope.dataUpdated = 0;
    $scope.watchCalled = 0;
    randomService.startService();

    $scope.getRandomData = function(){
        return randomService.getData();    
    }

    $scope.$watch("getRandomData()", function(newValue, oldValue){
        if(oldValue != newValue){
            $scope.data = newValue;
            $scope.dataUpdated++;
        }
            $scope.watchCalled++;
    });
});

2

আমি এই প্রশ্নে এসেছি কিন্তু এটি আমার সমস্যার মুখোমুখি হয়েছিল যে আমি সেটইন্টারভাল ব্যবহার করছিলাম যখন আমার কৌণিক $ অন্তর সরবরাহকারী ব্যবহার করা উচিত ছিল। এটি সেটটাইমআউটের ক্ষেত্রেও হয় (পরিবর্তে $ টাইমআউট ব্যবহার করুন)। আমি জানি এটি ওপি-র প্রশ্নের উত্তর নয়, তবে এটি আমাকে কিছুটা সহায়তা করতে পারে, কারণ এটি আমাকে সহায়তা করেছিল।


আপনি setTimeoutবা অন্য যে কোনও অ-কৌণিক ফাংশন ব্যবহার করতে পারেন তবে কলব্যাকের সাথে কোডটি মোড়াতে ভুলবেন না $scope.$apply()
চৌম্বকীয়

2

একই ধরণের সমস্যার সাথে পুরোপুরি ভিন্ন পদ্ধতির সাথে আমি অন্য থ্রেডে একটি দুর্দান্ত সমাধান পেয়েছি। উত্স: কৌণিক জেএস: $ রুটস্কোপের মান পরিবর্তিত হলে নির্দেশের মধ্যে নজর রাখে না $

মূলত সেখানকার সমাধানটি ব্যবহার না করতে বলে $watchকারণ এটি খুব ভারী সমাধান। পরিবর্তে তারা ব্যবহার করার প্রস্তাব দেয় $emitএবং $on

আমার সমস্যাটি ছিল আমার পরিষেবাতে পরিবর্তনশীল দেখা এবং নির্দেশে প্রতিক্রিয়া জানানো । এবং উপরের পদ্ধতিটি দিয়ে এটি খুব সহজ!

আমার মডিউল / পরিষেবা উদাহরণ:

angular.module('xxx').factory('example', function ($rootScope) {
    var user;

    return {
        setUser: function (aUser) {
            user = aUser;
            $rootScope.$emit('user:change');
        },
        getUser: function () {
            return (user) ? user : false;
        },
        ...
    };
});

তাই মূলত আমি আমার দেখিuser - যখনই এটি নতুন মানকে আমি $emitএকটি user:changeস্থিতি সেট করে ।

এখন আমার ক্ষেত্রে, আমি যে নির্দেশনাটি ব্যবহার করেছি:

angular.module('xxx').directive('directive', function (Auth, $rootScope) {
    return {
        ...
        link: function (scope, element, attrs) {
            ...
            $rootScope.$on('user:change', update);
        }
    };
});

এখন ডিরেক্টিভের আমি শুনতে $rootScopeএবং উপর প্রদত্ত পরিবর্তন - আমি যথাক্রমে প্রতিক্রিয়া জানিয়েছে। খুব সহজ এবং মার্জিত!


1

// পরিষেবা: (এখানে বিশেষ কিছু নেই)

myApp.service('myService', function() {
  return { someVariable:'abc123' };
});

// সিটিআরএল:

myApp.controller('MyCtrl', function($scope, myService) {

  $scope.someVariable = myService.someVariable;

  // watch the service and update this ctrl...
  $scope.$watch(function(){
    return myService.someVariable;
  }, function(newValue){
    $scope.someVariable = newValue;
  });
});

1

কিছুটা কুৎসিত, তবে আমি টগল করার জন্য আমার পরিষেবাতে স্কোপ ভেরিয়েবলের নিবন্ধকরণ যুক্ত করেছি:

myApp.service('myService', function() {
    var self = this;
    self.value = false;
    self.c2 = function(){};
    self.callback = function(){
        self.value = !self.value; 
       self.c2();
    };

    self.on = function(){
        return self.value;
    };

    self.register = function(obj, key){ 
        self.c2 = function(){
            obj[key] = self.value; 
            obj.$apply();
        } 
    };

    return this;
});

এবং তারপরে নিয়ামকটিতে:

function MyCtrl($scope, myService) {
    $scope.name = 'Superhero';
    $scope.myVar = false;
    myService.register($scope, 'myVar');
}

ধন্যবাদ। একটি ছোট প্রশ্ন: আপনি কেন thisসেই পরিষেবা থেকে ফিরে আসছেন self?
shrekuu

4
কারণ ভুল কখনও কখনও হয়ে যায়। ;-)
nclu

return this;আপনার নির্মাতাদের বাইরে ভাল অনুশীলন ;-)
কোডি

1

এই নিমজ্জনকারীটি দেখুন: এটি আমি সবচেয়ে সহজ উদাহরণ হিসাবে ভাবতে পারি

http://jsfiddle.net/HEdJF/

<div ng-app="myApp">
    <div ng-controller="FirstCtrl">
        <input type="text" ng-model="Data.FirstName"><!-- Input entered here -->
        <br>Input is : <strong>{{Data.FirstName}}</strong><!-- Successfully updates here -->
    </div>
    <hr>
    <div ng-controller="SecondCtrl">
        Input should also be here: {{Data.FirstName}}<!-- How do I automatically updated it here? -->
    </div>
</div>



// declare the app with no dependencies
var myApp = angular.module('myApp', []);
myApp.factory('Data', function(){
   return { FirstName: '' };
});

myApp.controller('FirstCtrl', function( $scope, Data ){
    $scope.Data = Data;
});

myApp.controller('SecondCtrl', function( $scope, Data ){
    $scope.Data = Data;
});

0

আমি এখানে কিছু ভয়ঙ্কর পর্যবেক্ষক নিদর্শন দেখেছি যা বড় অ্যাপ্লিকেশনগুলিতে মেমরি ফাঁস হয়।

আমি হয়ত একটু দেরি করে ফেলেছি তবে এটি এতটা সহজ।

ঘড়ির কাজটি রেফারেন্স পরিবর্তনগুলির (আদিম ধরণের) জন্য পর্যবেক্ষণ করে যদি আপনি অ্যারে পুশ জাতীয় কিছু ব্যবহার করতে চান তবে:

someArray.push(someObj); someArray = someArray.splice(0);

এটি রেফারেন্স আপডেট করবে এবং যে কোনও জায়গা থেকে ঘড়ি আপডেট করবে। একটি পরিষেবা গেটর পদ্ধতি সহ। আদিম যে কোনও কিছু স্বয়ংক্রিয়ভাবে আপডেট হবে।


0

আমি এই অংশে দেরি করেছি তবে উপরের পোস্ট করা উত্তরের চেয়ে আমি এটি করার একটি দুর্দান্ত উপায় খুঁজে পেয়েছি। পরিষেবা ভেরিয়েবলের মান ধরে রাখতে একটি ভেরিয়েবল বরাদ্দ করার পরিবর্তে, আমি সুযোগের সাথে যুক্ত একটি ফাংশন তৈরি করেছি, যা পরিষেবা ভেরিয়েবলটি ফেরত দেয়।

নিয়ামক

$scope.foo = function(){
 return aService.foo;
}

আমি মনে করি এটি আপনার যা করতে চাইবে তা করবে। আমার নিয়ামক এই প্রয়োগের সাথে আমার পরিষেবার মূল্য পরীক্ষা করে রাখছেন। সত্যি বলতে, এটি নির্বাচিত উত্তরের চেয়ে অনেক সহজ।


কেন এটি নিম্নমানযুক্ত ছিল .. আমি একই জাতীয় কৌশলটি বহুবার ব্যবহার করেছি এবং এটি কাজ করেছে।
undefined

0

আমি দুটি সহজ ইউটিলিটি পরিষেবা লিখেছি যা পরিষেবা বৈশিষ্ট্যগুলির পরিবর্তনগুলি ট্র্যাক করতে আমাকে সহায়তা করে।

আপনি যদি দীর্ঘ ব্যাখ্যাটি এড়াতে চান তবে আপনি স্ট্রেইটে যেতে পারেন জিএসফিডেলে

  1. WatchObj

mod.service('WatchObj', ['$rootScope', WatchObjService]);

function WatchObjService($rootScope) {
  // returns watch function
  // obj: the object to watch for
  // fields: the array of fields to watch
  // target: where to assign changes (usually it's $scope or controller instance)
  // $scope: optional, if not provided $rootScope is use
  return function watch_obj(obj, fields, target, $scope) {
    $scope = $scope || $rootScope;
    //initialize watches and create an array of "unwatch functions"
    var watched = fields.map(function(field) {
      return $scope.$watch(
        function() {
          return obj[field];
        },
        function(new_val) {
          target[field] = new_val;
        }
      );
    });
    //unregister function will unregister all our watches
    var unregister = function unregister_watch_obj() {
      watched.map(function(unregister) {
        unregister();
      });
    };
    //automatically unregister when scope is destroyed
    $scope.$on('$destroy', unregister);
    return unregister;
  };
}

এই পরিষেবাটি নিয়ামকটিতে নিম্নলিখিত উপায়ে ব্যবহার করা হয়েছে: ধরুন আপনার কাছে প্রোপ 1, 'প্রোপ 2', 'প্রোপ 3' বৈশিষ্ট্যযুক্ত একটি পরিষেবা "টেস্ট সার্ভিস" রয়েছে। আপনি 'প্রোপ 1' এবং 'প্রোপ 2' স্কোপটি দেখতে এবং বরাদ্দ করতে চান। ঘড়ি পরিষেবাটি দেখতে এটির মতো দেখাবে:

app.controller('TestWatch', ['$scope', 'TestService', 'WatchObj', TestWatchCtrl]);

function TestWatchCtrl($scope, testService, watch) {
  $scope.prop1 = testService.prop1;
  $scope.prop2 = testService.prop2;
  $scope.prop3 = testService.prop3;
  watch(testService, ['prop1', 'prop2'], $scope, $scope);
}

  1. প্রয়োগ দেখুন প্রবন্ধটি দুর্দান্ত, তবে আপনার পরিষেবাতে অ্যাসিক্রোনাস কোড থাকলে এটি যথেষ্ট নয়। সেক্ষেত্রে, আমি একটি দ্বিতীয় ইউটিলিটি ব্যবহার করি যা দেখতে দেখতে:

mod.service('apply', ['$timeout', ApplyService]);

function ApplyService($timeout) {
  return function apply() {
    $timeout(function() {});
  };
}

As ডাইজেস্ট লুপটি ট্রিগার করতে আমি আমার অ্যাসিঙ্ক কোডের শেষে এটি ট্রিগার করব। সে রকমই:

app.service('TestService', ['apply', TestService]);

function TestService(apply) {
  this.apply = apply;
}
TestService.prototype.test3 = function() {
  setTimeout(function() {
    this.prop1 = 'changed_test_2';
    this.prop2 = 'changed2_test_2';
    this.prop3 = 'changed3_test_2';
    this.apply(); //trigger $digest loop
  }.bind(this));
}

সুতরাং, এর সবগুলি এক সাথে দেখা হবে (আপনি এটি চালাতে বা ফিডল খুলতে পারেন ):

// TEST app code

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

app.controller('TestWatch', ['$scope', 'TestService', 'WatchObj', TestWatchCtrl]);

function TestWatchCtrl($scope, testService, watch) {
  $scope.prop1 = testService.prop1;
  $scope.prop2 = testService.prop2;
  $scope.prop3 = testService.prop3;
  watch(testService, ['prop1', 'prop2'], $scope, $scope);
  $scope.test1 = function() {
    testService.test1();
  };
  $scope.test2 = function() {
    testService.test2();
  };
  $scope.test3 = function() {
    testService.test3();
  };
}

app.service('TestService', ['apply', TestService]);

function TestService(apply) {
  this.apply = apply;
  this.reset();
}
TestService.prototype.reset = function() {
  this.prop1 = 'unchenged';
  this.prop2 = 'unchenged2';
  this.prop3 = 'unchenged3';
}
TestService.prototype.test1 = function() {
  this.prop1 = 'changed_test_1';
  this.prop2 = 'changed2_test_1';
  this.prop3 = 'changed3_test_1';
}
TestService.prototype.test2 = function() {
  setTimeout(function() {
    this.prop1 = 'changed_test_2';
    this.prop2 = 'changed2_test_2';
    this.prop3 = 'changed3_test_2';
  }.bind(this));
}
TestService.prototype.test3 = function() {
  setTimeout(function() {
    this.prop1 = 'changed_test_2';
    this.prop2 = 'changed2_test_2';
    this.prop3 = 'changed3_test_2';
    this.apply();
  }.bind(this));
}
//END TEST APP CODE

//WATCH UTILS
var mod = angular.module('watch_utils', []);

mod.service('apply', ['$timeout', ApplyService]);

function ApplyService($timeout) {
  return function apply() {
    $timeout(function() {});
  };
}

mod.service('WatchObj', ['$rootScope', WatchObjService]);

function WatchObjService($rootScope) {
  // target not always equals $scope, for example when using bindToController syntax in 
  //directives
  return function watch_obj(obj, fields, target, $scope) {
    // if $scope is not provided, $rootScope is used
    $scope = $scope || $rootScope;
    var watched = fields.map(function(field) {
      return $scope.$watch(
        function() {
          return obj[field];
        },
        function(new_val) {
          target[field] = new_val;
        }
      );
    });
    var unregister = function unregister_watch_obj() {
      watched.map(function(unregister) {
        unregister();
      });
    };
    $scope.$on('$destroy', unregister);
    return unregister;
  };
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class='test' ng-app="app" ng-controller="TestWatch">
  prop1: {{prop1}}
  <br>prop2: {{prop2}}
  <br>prop3 (unwatched): {{prop3}}
  <br>
  <button ng-click="test1()">
    Simple props change
  </button>
  <button ng-click="test2()">
    Async props change
  </button>
  <button ng-click="test3()">
    Async props change with apply
  </button>
</div>

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.