একটি কৌণিক পরিষেবা ফাংশনে ইনজেকশন $ সুযোগ ()


107

আমার একটি পরিষেবা আছে:

angular.module('cfd')
  .service('StudentService', [ '$http',
    function ($http) {
    // get some data via the $http
    var path = 'data/people/students.json';
    var students = $http.get(path).then(function (resp) {
      return resp.data;
    });     
    //save method create a new student if not already exists
    //else update the existing object
    this.save = function (student) {
      if (student.id == null) {
        //if this is new student, add it in students array
        $scope.students.push(student);
      } else {
        //for existing student, find this student using id
        //and update it.
        for (i in students) {
          if (students[i].id == student.id) {
            students[i] = student;
          }
        }
      }
    };

কিন্তু যখন আমি ফোন save(), আমি অ্যাক্সেস না থাকে $scope, এবং পেতে ReferenceError: $scope is not defined। সুতরাং যৌক্তিক পদক্ষেপটি (আমার জন্য), সংরক্ষণ () সংরক্ষণের সাথে প্রদান করা হয় $scope, এবং সুতরাং আমাকে অবশ্যই এটি সরবরাহ করতে / ইনজেক্ট করতে হবে service। সুতরাং যদি আমি এটির মতো করি:

  .service('StudentService', [ '$http', '$scope',
                      function ($http, $scope) {

আমি নিম্নলিখিত ত্রুটি পেয়েছি:

ত্রুটি: [ject ইনজেক্টর: আনআরপি] অজানা সরবরাহকারী: $ স্কোপপ্রাইডার <- $ স্কোপ <- স্টুডেন্ট সার্ভিস

ত্রুটির লিঙ্কটি (বাহ যে ঝরঝরে!) এটি আমাকে ইনজেক্টর সম্পর্কিত সম্পর্কিত জানতে দেয় এবং জেএস ফাইলগুলি ঘোষণার আদেশের সাথে করতে হতে পারে। আমি তাদেরগুলিতে পুনরায় অর্ডার করার চেষ্টা করেছি index.html, তবে আমি মনে করি এটি আরও সহজ কিছু, যেমন আমি তাদের ইনজেকশন দিচ্ছি।

কৌণিক-ইউআই এবং কৌণিক-ইউআই-রাউটার ব্যবহার করে

উত্তর:


183

$scopeআপনি কন্ট্রোলার মধ্যে ইনজেকশনের হচ্ছে দেখুন কিছু সার্ভিস (ইঞ্জেকশনভিত্তিক কাপড় বাকি মত) নয়, কিন্তু একটি ব্যাপ্তি অবজেক্ট। অনেক স্কোপ অবজেক্ট তৈরি করা যায় (সাধারণত অভিভাবকের সুযোগ থেকে উত্তরাধিকার সূত্রে প্রাপ্ত হয়)। সমস্ত $rootScopeস্কোপের মূল হ'ল এবং আপনি যে $new()কোনও সুযোগের পদ্ধতি (সহ $rootScope) ব্যবহার করে একটি নতুন শিশু-সুযোগ তৈরি করতে পারেন ।

একটি ব্যাপ্তির উদ্দেশ্য আপনার অ্যাপ্লিকেশনটির উপস্থাপনা এবং ব্যবসায়িক যুক্তি "একসাথে আটকানো"। $scopeকোনও পরিষেবাতে পাস করার পক্ষে এটি খুব বেশি অর্থবোধ করে না ।

পরিষেবাগুলি হ'ল সিঙ্গলটন অবজেক্টস (অন্যান্য জিনিসের মধ্যে) ডেটা ভাগ করার জন্য ব্যবহৃত হয় (উদাহরণস্বরূপ বেশ কয়েকটি নিয়ন্ত্রণকারীদের মধ্যে) এবং সাধারণত কোডের পুনরায় ব্যবহারযোগ্য টুকরাগুলি encapsulate (যেহেতু তারা ইনজেকশনের মাধ্যমে আপনার অ্যাপ্লিকেশানের যে কোনও অংশে তাদের "পরিষেবাদি" সরবরাহ করতে পারে যা তাদের প্রয়োজন: নিয়ন্ত্রক, নির্দেশাবলী, ফিল্টার, অন্যান্য পরিষেবাদি ইত্যাদি)।

আমি নিশ্চিত, বিভিন্ন পদ্ধতি আপনার পক্ষে কাজ করবে।
এটি StudentServiceহ'ল : যেহেতু শিক্ষার্থীদের ডেটা নিয়ে কাজ করার দায়িত্বে রয়েছেন, তাই আপনার StudentServiceকাছে শিক্ষার্থীদের একটি অ্যারে রাখা থাকতে পারে এবং যারাই আগ্রহী (যেমন আপনার $scope) তার সাথে এটি "ভাগ" করতে দিন । এটি আরও দৃ sense়তর করে তোলে, যদি সেখানে অন্যান্য মতামত / নিয়ন্ত্রণকারী / ফিল্টার / পরিষেবাদিগুলির সেই তথ্যে অ্যাক্সেস থাকা দরকার (যদি এখনই কিছু না থাকে তবে তারা শীঘ্রই পপিং শুরু করলে অবাক হবেন না)।
প্রতিবার নতুন শিক্ষার্থী যুক্ত হওয়ার সাথে সাথে (পরিষেবাদির save()পদ্ধতিটি ব্যবহার করে ), সেবার নিজস্ব শিক্ষার্থীদের আরে আপডেট করা হবে এবং অ্যারে ভাগ করে নেওয়া প্রতিটি বস্তু ভাগ করে নেওয়ার সাথে সাথে স্বয়ংক্রিয়ভাবে আপডেট হবে।

উপরে বর্ণিত পদ্ধতির উপর ভিত্তি করে, আপনার কোডটি দেখতে এরকম হতে পারে:

angular.
  module('cfd', []).

  factory('StudentService', ['$http', '$q', function ($http, $q) {
    var path = 'data/people/students.json';
    var students = [];

    // In the real app, instead of just updating the students array
    // (which will be probably already done from the controller)
    // this method should send the student data to the server and
    // wait for a response.
    // This method returns a promise to emulate what would happen 
    // when actually communicating with the server.
    var save = function (student) {
      if (student.id === null) {
        students.push(student);
      } else {
        for (var i = 0; i < students.length; i++) {
          if (students[i].id === student.id) {
            students[i] = student;
            break;
          }
        }
      }

      return $q.resolve(student);
    };

    // Populate the students array with students from the server.
    $http.get(path).then(function (response) {
      response.data.forEach(function (student) {
        students.push(student);
      });
    });

    return {
      students: students,
      save: save
    };     
  }]).

  controller('someCtrl', ['$scope', 'StudentService', 
    function ($scope, StudentService) {
      $scope.students = StudentService.students;
      $scope.saveStudent = function (student) {
        // Do some $scope-specific stuff...

        // Do the actual saving using the StudentService.
        // Once the operation is completed, the $scope's `students`
        // array will be automatically updated, since it references
        // the StudentService's `students` array.
        StudentService.save(student).then(function () {
          // Do some more $scope-specific stuff, 
          // e.g. show a notification.
        }, function (err) {
          // Handle the error.
        });
      };
    }
]);

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

/* DON'T DO THAT   */  
var clear = function () { students = []; }

/* DO THIS INSTEAD */  
var clear = function () { students.splice(0, students.length); }

এই সংক্ষিপ্ত ডেমোটিও দেখুন


সামান্য আপডেট:

কোনও পরিষেবা ব্যবহারের কথা বলার সময় যে বিভ্রান্তি দেখা দিতে পারে তা এড়াতে কয়েকটি শব্দ, তবে এটি service()ফাংশনটি দিয়ে তৈরি না করে।

দস্তাবেজগুলি$provide উদ্ধৃত করে :

একটি কৌণিক পরিষেবা একটি পরিষেবা কারখানার দ্বারা তৈরি একটি সিঙ্গলটন অবজেক্ট । এই পরিষেবা কারখানাগুলি এমন ফাংশন যা ঘুরেফিরে কোনও পরিষেবা সরবরাহকারী তৈরি করে । পরিষেবা প্রদানকারীর কন্সট্রাকটর ফাংশন আছে। তাত্ক্ষণিক হলে তাদের অবশ্যই একটি সম্পত্তি বলা উচিত $get, যা পরিষেবা কারখানার ফাংশন ধারণ করে ।
[...]
... $provideপরিষেবা সরবরাহকারীর নির্দিষ্টকরণ ছাড়াই পরিষেবার নিবন্ধকরণের জন্য অতিরিক্ত সহায়ক পদ্ধতি রয়েছে:

  • সরবরাহকারী (সরবরাহকারী) - service ইনজেক্টর সহ কোনও পরিষেবা সরবরাহকারীর নিবন্ধন করে
  • ধ্রুবক ( আপত্তি ) - সরবরাহকারী এবং পরিষেবাদি দ্বারা অ্যাক্সেস করা যায় এমন একটি মান / অবজেক্ট নিবন্ধভুক্ত করে।
  • মান ( আপত্তি ) - এমন একটি মান / অবজেক্ট নিবন্ধন করে যা কেবল পরিষেবাগুলি দ্বারা সরবরাহ করা যায়, সরবরাহকারী নয়।
  • কারখানা (fn) - একটি পরিষেবা কারখানার ফাংশন নিবন্ধন করে, fn, যা কোনও পরিষেবা সরবরাহকারী বস্তুতে আবৃত থাকবে, যার $ সম্পত্তি প্রাপ্তিতে প্রদত্ত কারখানার ফাংশন থাকবে।
  • পরিষেবাদি (শ্রেণি) - একটি কনস্ট্রাক্টর ফাংশন নিবন্ধন করে, শ্রেণি যা পরিষেবা সরবরাহকারী অবজেক্টে আবৃত থাকবে, যার property সম্পত্তি প্রাপ্ত প্রদায়ক কনস্ট্রাক্টর ফাংশনটি ব্যবহার করে কোনও নতুন অবজেক্ট ইনস্ট্যান্ট করবে।

মূলত, এটি যা বলে তা হ'ল প্রতিটি কৌণিক পরিষেবাটি ব্যবহার করে নিবন্ধভুক্ত $provide.provider(), তবে সরল পরিষেবাগুলির জন্য "শর্টকাট" পদ্ধতি রয়েছে (যার মধ্যে দুটি হ'ল service()এবং factory())।
এটি সমস্ত কোনও পরিষেবায় "ফুটে যায়", সুতরাং আপনি কোন পদ্ধতিটি ব্যবহার করবেন তা তত বেশি তাত্পর্য দেয় না (যতক্ষণ না আপনার পরিষেবার প্রয়োজনগুলি সেই পদ্ধতিতে আওতাভুক্ত হয়)।

বিটিডাব্লু, providerবনাম serviceবনাম factoryঅ্যাংুলার নতুন আগতদের কাছে একটি বিভ্রান্তিকর ধারণা, তবে ভাগ্যক্রমে জিনিসগুলি সহজ করার জন্য প্রচুর সংস্থান (এখানে এসও তে) রয়েছে। (শুধু সন্ধান করুন।)

(আমি আশা করি এটি পরিষ্কার হয়ে যায় - এটি না হলে আমাকে জানান let)


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

3
@ ক্রিসফ্রিসিনা: কিছুটা ব্যাখ্যা দিয়ে উত্তর আপডেট করেছেন। মূলত, আপনি যদি ব্যবহার করেন serviceবা factory- আপনি আপনার এবং কৌণিক পরিষেবা দিয়ে শেষ করেন তবে এটি খুব বেশি পার্থক্য করে না । কেবল নিশ্চিত হয়ে নিন যে আপনি প্রত্যেকে কীভাবে কাজ করে তা বুঝতে এবং এটি যদি আপনার প্রয়োজন অনুসারে হয়।
gklpak

চমৎকার পোস্ট! এটা আমাকে অনেক সাহায্য করেছে !
ওনি 1

ধন্যবাদ ভাই! অনুরূপ বিষয়ে একটি চমৎকার নিবন্ধ এখানে stsc3000.github.io/blog/2013/10/26/…
Terafor

@ এক্স্পার্টসিসটেমটি কি $scope.studentsখালি খালি হবে, যদি এজ্যাক্স কলটি শেষ না হয়? বা $scope.studentsআংশিকভাবে পূরণ করা যাচ্ছে, এই কোড ব্লক যদি কাজ চলছে? students.push(student);
Yc Zhang

18

$scopeপরিষেবাটির অভ্যন্তরে সংশোধন করার চেষ্টা করার পরিবর্তে , আপনি $watchপরিবর্তনের জন্য আপনার পরিষেবাতে কোনও সম্পত্তি দেখার জন্য এবং তারপরে একটি সম্পত্তি আপডেট করার জন্য আপনার নিয়ামকের মধ্যে একটি প্রয়োগ করতে পারেন $scope। আপনি একটি নিয়ামক চেষ্টা করতে পারেন একটি উদাহরণ এখানে:

angular.module('cfd')
    .controller('MyController', ['$scope', 'StudentService', function ($scope, StudentService) {

        $scope.students = null;

        (function () {
            $scope.$watch(function () {
                return StudentService.students;
            }, function (newVal, oldVal) {
                if ( newValue !== oldValue ) {
                    $scope.students = newVal;
                }
            });
        }());
    }]);

একটি বিষয় লক্ষণীয় হ'ল আপনার সেবার মধ্যে, studentsসম্পত্তিটি দৃশ্যমান হওয়ার জন্য, এটি পরিষেবা অবজেক্টে থাকা বা এটির thisমতো হওয়া দরকার:

this.students = $http.get(path).then(function (resp) {
  return resp.data;
});

12

ভাল (একটি দীর্ঘ) ... আপনি যদি কোনও পরিষেবার ভিতরে প্রবেশাধিকারের জন্য জোর$scope দিয়ে থাকেন তবে আপনি এটি করতে পারেন:

একটি গেটর / সেটার পরিষেবা তৈরি করুন

ngapp.factory('Scopes', function (){
  var mem = {};
  return {
    store: function (key, value) { mem[key] = value; },
    get: function (key) { return mem[key]; }
  };
});

এটি ইনজেক্ট করুন এবং এতে নিয়ামক সুযোগ সংরক্ষণ করুন

ngapp.controller('myCtrl', ['$scope', 'Scopes', function($scope, Scopes) {
  Scopes.store('myCtrl', $scope);
}]);

এখন, অন্য একটি পরিষেবার ভিতরে সুযোগ পান get

ngapp.factory('getRoute', ['Scopes', '$http', function(Scopes, $http){
  // there you are
  var $scope = Scopes.get('myCtrl');
}]);

স্কোপগুলি কীভাবে ধ্বংস হচ্ছে?
জে.কে।

9

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


আমি বুঝতে পারছি তুমি কি বলছ। যাইহোক, আমার ক্ষেত্রে, আমার অনেকগুলি নিয়ামক রয়েছে এবং আমি তাদের স্কোপগুলি $ ঘড়ির একটি খুব সমান সেট দিয়ে কনফিগার করতে চাই। আপনি কীভাবে / কোথায় করবেন? বর্তমানে, আমি প্রকৃতপক্ষে এমন একটি পরিষেবাতে প্যারামিটার হিসাবে সুযোগটি পাস করি যারা $ ঘড়িগুলি সেট করে।
মরিটজ

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

@ টিমিন নিউট্রন যা স্কোপটি অতিক্রম করার চেয়ে অনেক বেশি ভাল লাগে, আমি পরের বারের মতো দৃশ্যটি সামনে আসার চেষ্টা করব! ধন্যবাদ!
মরিজ

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

3

আপনি আপনার পরিষেবাটি সুযোগ থেকে সম্পূর্ণ অজানা করতে পারেন, তবে আপনার নিয়ামকটিতে সুযোগটি অযৌক্তিকভাবে আপডেট করার অনুমতি দেয়।

আপনি যে সমস্যাটি করছেন তা হ'ল আপনি জানেন না যে এইচটিপি কলগুলি অবিচ্ছিন্নভাবে করা হয়, যার অর্থ আপনি যতটা সম্ভব তত্ক্ষণাত মান পাবেন না। এই ক্ষেত্রে,

var students = $http.get(path).then(function (resp) {
  return resp.data;
}); // then() returns a promise object, not resp.data

এটি কাছাকাছি আসার একটি সহজ উপায় আছে এবং এটি কলব্যাক ফাংশন সরবরাহ করে।

.service('StudentService', [ '$http',
    function ($http) {
    // get some data via the $http
    var path = '/students';

    //save method create a new student if not already exists
    //else update the existing object
    this.save = function (student, doneCallback) {
      $http.post(
        path, 
        {
          params: {
            student: student
          }
        }
      )
      .then(function (resp) {
        doneCallback(resp.data); // when the async http call is done, execute the callback
      });  
    }
.controller('StudentSaveController', ['$scope', 'StudentService', function ($scope, StudentService) {
  $scope.saveUser = function (user) {
    StudentService.save(user, function (data) {
      $scope.message = data; // I'm assuming data is a string error returned from your REST API
    })
  }
}]);

ফর্ম:

<div class="form-message">{{message}}</div>

<div ng-controller="StudentSaveController">
  <form novalidate class="simple-form">
    Name: <input type="text" ng-model="user.name" /><br />
    E-mail: <input type="email" ng-model="user.email" /><br />
    Gender: <input type="radio" ng-model="user.gender" value="male" />male
    <input type="radio" ng-model="user.gender" value="female" />female<br />
    <input type="button" ng-click="reset()" value="Reset" />
    <input type="submit" ng-click="saveUser(user)" value="Save" />
  </form>
</div>

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



0

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

(function () {
    getDataFactory = function ($http)
    {
        return {
            callWebApi: function (reqData)
            {
                var dataTemp = {
                    Page: 1, Take: 10,
                    PropName: 'Id', SortOrder: 'Asc'
                };

                return $http({
                    method: 'GET',
                    url: '/api/PatientCategoryApi/PatCat',
                    params: dataTemp, // Parameters to pass to external service
                    headers: { 'Content-Type': 'application/Json' }
                })                
            }
        }
    }
    patientCategoryController = function ($scope, getDataFactory) {
        alert('Hare');
        var promise = getDataFactory.callWebApi('someDataToPass');
        promise.then(
            function successCallback(response) {
                alert(JSON.stringify(response.data));
                // Set this response data to scope to use it in UI
                $scope.gridOptions.data = response.data.Collection;
            }, function errorCallback(response) {
                alert('Some problem while fetching data!!');
            });
    }
    patientCategoryController.$inject = ['$scope', 'getDataFactory'];
    getDataFactory.$inject = ['$http'];
    angular.module('demoApp', []);
    angular.module('demoApp').controller('patientCategoryController', patientCategoryController);
    angular.module('demoApp').factory('getDataFactory', getDataFactory);    
}());

0

স্কোপ ভেরিয়েবলগুলির সাথে ডিল করার কোডটি নিয়ামক হিসাবে যেতে হবে এবং পরিষেবা কলগুলি পরিষেবাতে যেতে হবে।

আপনি উদ্বুদ্ধ করতে পারেন $rootScopeব্যবহারের উদ্দেশ্যে $rootScope.$broadcastএবং $rootScope.$on

অন্যথায় ইনজেকশন এড়ান $rootScope। দেখা

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