Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>The typical answer for this is that you should use a service for this purpose. Here's some general information about this: <a href="http://docs.angularjs.org/guide/dev_guide.services.understanding_services" rel="nofollow">http://docs.angularjs.org/guide/dev_guide.services.understanding_services</a></p> <p>Here is a <a href="http://plnkr.co/edit/g6Nmnc?p=preview" rel="nofollow">plunk with code modeled after your own starting example</a>:</p> <p><strong>Example code:</strong></p> <pre><code>var app = angular.module('savingServiceDemo', []); app.service('savingService', function() { return { somethingOrOther: { save: function(obj, callback) { console.log('Saved:'); console.dir(obj); callback(obj, {}); } } }; }); app.directive('saveable', ['savingService', function(savingService) { return { restrict: 'A', link: function(scope) { scope.saveModel = function(question) { savingService.somethingOrOther.save( { id: question.id, answer: question.value }, function(response, getResponseHeaders) { // a bunch of post-processing } ); } } }; }]); app.controller('questionController', ['$scope', function($scope) { $scope.question = { question: 'What kind of AngularJS object should you create to contain data access or network communication logic?', id: 1, value: '' }; }]); </code></pre> <p><strong>The relevant HTML markup:</strong></p> <pre><code>&lt;body ng-controller="questionController"&gt; &lt;h3&gt;Question&lt;h3&gt; &lt;h4&gt;{{question.question}}&lt;/h4&gt; Your answer: &lt;input ng-model="question.value" saveable ng-blur="saveModel(question)" /&gt; &lt;/body&gt; </code></pre> <p><strong>An alternative using only <code>factory</code> and the existing ngResource service:</strong></p> <p>However, you could also utilize <code>factory</code> and ngResource in a way that would let you reuse some of the common "saving logic", while still giving you the ability to provide variation for distinct types of objects / data that you wish to save or query. And, this way still results in just a single instantiation of the saver for your specific object type.</p> <p><strong>Example using MongoLab collections</strong></p> <p>I've done something like this to make it easier to use MongoLab collections.</p> <p><a href="http://plnkr.co/edit/fa9Mxn?p=preview" rel="nofollow">Here's a plunk.</a></p> <p>The gist of the idea is this snippet:</p> <pre><code> var dbUrl = "https://api.mongolab.com/api/1/databases/YOURDB/collections"; var apiKey = "YOUR API KEY"; var collections = [ "user", "question", "like" ]; for(var i = 0; i &lt; collections.length; i++) { var collectionName = collections[i]; app.factory(collectionName, ['$resource', function($resource) { var resourceConstructor = createResource($resource, dbUrl, collectionName, apiKey); var svc = new resourceConstructor(); // modify behavior if you want to override defaults return svc; }]); } </code></pre> <p><strong>Notes:</strong></p> <ul> <li><code>dbUrl</code> and <code>apiKey</code> would be, of course, specific to your own MongoLab info</li> <li>The array in this case is a group of distinct collections that you want individual ngResource-derived instances of</li> <li>There is a <code>createResource</code> function defined (which you can see in the plunk and in the code below) that actually handles creating a constructor with an ngResource prototype.</li> <li>If you wanted, you could modify the <code>svc</code> instance to vary its behavior by collection type</li> <li>When you blur the input field, this will invoke the dummy <code>consoleLog</code> function and just write some debug info to the console for illustration purposes.</li> <li>This also prints the number of times the <code>createResource</code> function itself was called, as a way to demonstrate that, even though there are actually two controllers, <code>questionController</code> and <code>questionController2</code> asking for the same injections, the factories get called only 3 times in total.</li> <li>Note: updateSafe is a function I like to use with MongoLab that allows you to apply a partial update, basically a PATCH. Otherwise, if you only send a few properties, the entire document will get overwritten with ONLY those properties! No good!</li> </ul> <p><strong>Full code:</strong></p> <p><em>HTML:</em></p> <pre><code> &lt;body&gt; &lt;div ng-controller="questionController"&gt; &lt;h3&gt;Question&lt;h3&gt; &lt;h4&gt;{{question.question}}&lt;/h4&gt; Your answer: &lt;input ng-model="question.value" saveable ng-blur="save(question)" /&gt; &lt;/div&gt; &lt;div ng-controller="questionController2"&gt; &lt;h3&gt;Question&lt;h3&gt; &lt;h4&gt;{{question.question}}&lt;/h4&gt; Your answer: &lt;input ng-model="question.value" saveable ng-blur="save(question)" /&gt; &lt;/div&gt; &lt;/body&gt; </code></pre> <p><em>JavaScript:</em></p> <pre><code>(function() { var app = angular.module('savingServiceDemo', ['ngResource']); var numberOfTimesCreateResourceGetsInvokedShouldStopAt3 = 0; function createResource(resourceService, resourcePath, resourceName, apiKey) { numberOfTimesCreateResourceGetsInvokedShouldStopAt3++; var resource = resourceService(resourcePath + '/' + resourceName + '/:id', { apiKey: apiKey }, { update: { method: 'PUT' } } ); resource.prototype.consoleLog = function (val, cb) { console.log("The numberOfTimesCreateResourceGetsInvokedShouldStopAt3 counter is at: " + numberOfTimesCreateResourceGetsInvokedShouldStopAt3); console.log('Logging:'); console.log(val); console.log('this ='); console.log(this); if (cb) { cb(); } }; resource.prototype.update = function (cb) { return resource.update({ id: this._id.$oid }, angular.extend({}, this, { _id: undefined }), cb); }; resource.prototype.updateSafe = function (patch, cb) { resource.get({id:this._id.$oid}, function(obj) { for(var prop in patch) { obj[prop] = patch[prop]; } obj.update(cb); }); }; resource.prototype.destroy = function (cb) { return resource.remove({ id: this._id.$oid }, cb); }; return resource; } var dbUrl = "https://api.mongolab.com/api/1/databases/YOURDB/collections"; var apiKey = "YOUR API KEY"; var collections = [ "user", "question", "like" ]; for(var i = 0; i &lt; collections.length; i++) { var collectionName = collections[i]; app.factory(collectionName, ['$resource', function($resource) { var resourceConstructor = createResource($resource, dbUrl, collectionName, apiKey); var svc = new resourceConstructor(); // modify behavior if you want to override defaults return svc; }]); } app.controller('questionController', ['$scope', 'user', 'question', 'like', function($scope, user, question, like) { $scope.question = { question: 'What kind of AngularJS object should you create to contain data access or network communication logic?', id: 1, value: '' }; $scope.save = function(obj) { question.consoleLog(obj, function() { console.log('And, I got called back'); }); }; }]); app.controller('questionController2', ['$scope', 'user', 'question', 'like', function($scope, user, question, like) { $scope.question = { question: 'What is the coolest JS framework of them all?', id: 1, value: '' }; $scope.save = function(obj) { question.consoleLog(obj, function() { console.log('You better have said AngularJS'); }); }; }]); })(); </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload