I have a property in my angular model that needs to be calculated before sending to the server. I have a save() method in my controller that sends the model to the $http service to save the data. It goes something like this:
$scope.user.customerId = lookup($scope.user.userId);
Where lookup() looks up the value in a local array. The customerID value is currently not used in the view at all, but the server wants the customerID.
My question is: Is there a best practice around calculating values?
Should this be done in a $watch, implicitly in an object getter, or should this be done while saving, either in the controller or in a service? Something else entirely?
I appreciate any input.
A service would be a better choice than the controller, since customerID won't be used in a view.
But if customerID is only used on the server, I would recommend using a request interceptor. You can read more about it in the official docs.
Hopefully this helps:
module.factory('customerIdInterceptor', [function() {
var requestInterceptor = {
request: function(config) {
// request payload is in config.data
// calculate customerId and put it where you want it
}
};
return requestInterceptor;
}]);
module.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('customerIdInterceptor');
}]);
Related
In my web app, I would like to load all of the user data at the beginning, in the run method and pass the data to the other controllers to be shown to the user in the dashboard.
So lets say I have a data structure on the server
data = {
x : 30,
y: 20
}
I would like to get it in one http requests (instead of creating multiple http requests and creating multiple promises)
The http request I run in the run method of the app
service.getDataFromServer = function(){
return $http.get('/admin/data').then(function(response) {
data = response.data;
});
};
This will create a promise.
I would like to take this promise and pass it to other controllers to be used.
My first question is how can I do it so the data from the promise will bind to the data I am about to show to the user.
The second question is, can I use the structure fields before the promise is even resolved?
for example
$scope.x = data.x
And by data I mean the data which is about to be resolved
Thanks
I would like to get it in one http requests (instead of creating multiple http requests and creating multiple promises)
After getting response from http call,save the data in factory/services so,you can use is at another location like controller in your case by injecting it which is most recommended.
I would like to take this promise and pass it to other controllers to be used.
how can I do it so the data from the promise will bind to the data I am about to show to the user.
make http call and save the promise.
service.getDataFromServer = function() {
var promise = $http.get('test.json');
service.savePromise(promise);
}
and
get saved promise.
.controller('testCtrl', function(service) {
service.getSavedPromise().then(function(response){
console.log(response.data)
})
})
Plunker here
The second question is, can I use the structure fields before the promise is even resolved? for example
$scope.x = data.x
// data is still undefined as promise is not resolved.so,you will get TypeError
What you can do best here,you can merge data to your existing data object/array,so,Angular two way binding can do rest of the things for you.
I'm looking for some input on exactly how to accomplish the following design pattern.
Background: I have two factories and a controller:
FirstFactory: This is the data storage that contains all the data the application relies on to function
SecondFactory: This is a list of $http.get methods. The getAllCities method just returns a promise
Controller: This is where the data resolves from SecondFactory and then is set into FirstFactory.journey.
Now currently the controller works fine but I am trying to have the data, from SecondFactory.getAllCities() resolve itself in the FirstFactory on runtime instead of waiting for the Controller to update it.
So currently I have a controller that does the following:
build = function() {
return SecondFactory.getAllCities()
.then(function(response) {
FirstFactory.journey = response;
});
};
This works fine and updates the factory with a the data returned from the method SecondFactory.getAllCities(). However I feel that the controller shouldn't be what sets up the default or init data set, I think the factory should accomplish this on it's own.
I assumed, probably incorrectly, that the following would work as instead of doing the call to the SecondFactory inside the controller, I was just moving this call to the FirstFactory so it can resolve itself when its instantiated instead of relying on the controller to populate the FirstFactory.journey with data.
var build;
//This is a call to a factory that contains the data
//I want to grab and store this in my factory on run
build = function() {
SecondFactory.getAllCities()
.then(function(response) {
//Why does this not get returned?
console.log(response);
return response
})
};
//This is the factory object that is returned
return {
journey: build()
}
However the above doesn't work. The console.log in the build function contains the data I require but it isn't being returned by that function. Is this an issue with my implementation of the promise or a broader design pattern issue?
I have been struggling to find a consistent and good example of a put operation using AngularJS $resource. An example of when I want to update, but can't seem to is located here: AngularJS PUT on voting application to REST Service
At the core, I need to understand the best practice/normal way to conduct a put operation both for form submissions or in the voting application mentioned in my post above. Does anyone have a good example that demonstrates a put?
If you're creating a new entity in your data store you want to use POST/save. If you're updating the data associated with an already existing entity in your data store you want to use PUT/update. Patch is usually reserved for when you just want to update a subset of the entity data.
Look at the RFC
Several applications extending the Hypertext Transfer Protocol (HTTP)
require a feature to do partial resource modification. The existing
HTTP PUT method only allows a complete replacement of a document. This
proposal adds a new HTTP method, PATCH, to modify an existing HTTP
resource.
You would supply an id with both PUT and PATCH operations. You would not supply one with a POST operation.
When we load our angular forms it is done one of two ways usually. If the form is loaded when we are creating a new entity then we won't have an id. We will know this in the controller and will call resource.save. If we supply the controller loading the form with an id that's used to pull data from an endpoint to populate the form, we now have the id we can use to do a resource.update or resource.patch operations depending on how much of the entity we are updating.
Here's an example save function that handles both update and save operations. Here we check to see if an id was supplied via the route before we make our resource call.
angular.module('appModule').controller('ExampleCtrl',
['$scope', '$routeParams',
function($scope, $routeParams) {
$scope.saveForm = function () {
//Do input validation before you make a resource call
if ($routeParams.id) {
//call resource update since we have an id
}
else {
//call resource save since we don't have an id
}
};
}]);
Here's the example from the angularjs documentation:
How to create a custom PUT request:
var app = angular.module('app', ['ngResource', 'ngRoute']);
// Some APIs expect a PUT request in the format URL/object/ID
// Here we are creating an 'update' method
app.factory('Notes', ['$resource', function($resource) {
return $resource('/notes/:id', null,
{
'update': { method:'PUT' }
});
}]);
// In our controller we get the ID from the URL using ngRoute and $routeParams
// We pass in $routeParams and our Notes factory along with $scope
app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
function($scope, $routeParams, Notes) {
// First get a note object from the factory
var note = Notes.get({ id:$routeParams.id });
$id = note.id;
// Now call update passing in the ID first then the object you are updating
Notes.update({ id:$id }, note);
// This will PUT /notes/ID with the note object in the request payload
}]);
I have a custom Web API written in .NET that returns user's information that will be used in my AngularJS application. I want to be able to call my API once, and then use that returned JSON across my entire AngularJS application without having to recall the API within each of my controllers.
I currently have a factory of services, one of which returns all of the client's details I need to use the in rest of the services.
.factory('customApiService', function ($resource) {
return {
userInfo: function(userId, callback){
var api = $resource('../../api/UserInfo/:userId', {
userId: userId
}, {
fetch: 'JSONP',
'query': { isArray: false }
});
api.fetch(function (response) {
callback(response);
});
}
}
)
Now I don't want to call this userInfo service in every controller, but I do want the data to be passed into each without calling my API multiple times.
customApiService.userInfo(userId, function (d) {
var gaProfileId = d.gaProfileId;
var yelpId = d.yelpId;
var tripAdvisorId = d.tripAdvisorId;
var facebookPageName = d.facebookPage;
var twitterHandle = d.twitterHandle;
var clientName = d.clientName;
var searchlightAccountId = d.searchlightAccountId;
var searchlightDomain = d.searchlightDomainId;
}
You can try global variables .
use a $rootScope https://docs.angularjs.org/guide/scope
$rootScope is available in all controllers an templates .Just inject $rootscope in your controller or wherever required.
From what I read of your description and responses to other questions, it sounds like you're trying to make an asynchronous call before the rest of your app starts up. This is possible, but complex, and sort of voids the point of Angular in the first place. As I see it, you have two options:
QUICK HACK: If you really want this kind of behavior, why start your app at all? Do your request first, before you define your app in the first place, then define your app in the result handler for the request.
RIGHT WAY: Alter the behavior of your services and controllers to tolerate not having enough information to fully start. A lot of times this is less difficult than it sounds. Usually you can just chain a promise into their initialization block of code to wait for the data you need. Take a look at Brian Ford's "Angular Modal" project, at the lines of code I've highlighted here:
https://github.com/btford/angular-modal/blob/master/modal.js#L25-L36
This technique sets up a promise to return from the function. If the data it needs is already loaded from the service, it resolves the promise immediately. Otherwise, it makes the call to get what it's after, and you can see later (line 39) that the module uses promise.then() to wait until it has the data it needs to run.
This is a great pattern for both controllers and services when working with asynchronous data.
If using a $resource call instead, note that most $resource calls return a promise in a property called $promise. You can do something like this:
var MyController = function($scope) {
// This will get set soon!
$scope.myData = null;
var myResource = $resource('/path/to/:someId', { someId: '#id' });
myResource.get({ someId: 1 }).$promise.then(function(data) {
$scope.myData = data;
});
};
You can do more things in the .then() resolution callback for the promise, like initialize more parts of your controller, etc. There are also ways you can delay starting your entire controller until the resource is available. One really cool way is if you happen to be using the Angular ui-router module, there is a "resolve" option when defining each route. You can use that to call the $resource as shown above, and ui-router will wait to start your controller/view until it has what it needs.
I'm using angular routing for a SPA with a sidebar (on index.html) that loads a list of categories from a categoryListController, which has a categoryData $resource service injected for retrieving the category list.
Then i have a template, addCategory.html which adds a category with the help of a addCategoryController, which also uses categoryData $resource service.
$scope.categories = categoryData.query(); //categoryListController (for sidebar)
categoryData.save(newCategory) // on addCategoryController (for addCategory.html)
The problem is, the sidebar won't update unless I refresh the entire page. I'm thinking i've got to somehow tell the categoryListController to refresh, but i'm not sure how to do that. I can do $scope.categories.push(newCategory) right after categoryData.save(newCategory), and get the new category showing immediately on addCategory.html, but i don't think that's the answer for my sidebar, unless this is something that needs to be handled with $rootscope? I'm not sure. Thanks
One of the approach that you can take here to update the list of categories in categoryListController would be to use $rootScope to broadcast message detailing the category added.
Catch this message in the list controller to either fetch the list again from server or use the newly added item send using the broadcast message to the list.
Something like this in the Add controller
$rootScope.$broadcast('categoryAdded', { 'category': newcategoryObject });
Something like this in list controller
$scope.$on('categoryAdded', function (event, args) {
$scope.categories.push(args.category);
});
You can inject $rootScope as a dependency into the controller.
You can do a similar thing by creating a CategoryList service too. Since service are singleton by nature and can be shared across controllers, using the service approach you would define a CategoryList service with methods to get and `add' categories and bind to data returned by this service.
You should create a service that share the data structure and care of managing the content.
Something like this:
angular.service('categoryService', function() {
var categories = [], initilized;
return {
this.getCategories = function() {
if (!initialized) {
// call resource to fulfill the categories array
initialized = true;
}
// you cold return a promise that would be resolved as soon
// as you get the first response from server
return categories;
});
this.addCategory = function(category) {
// code to call $resource, add the category and update the
// categories array, shared between both controllers
//
// you could return the promise for adding the content
});
this.removeCategory = ...
};
});
You wouldn't need to even call $resource, this service would care of any need of persisting. Of course, you might change and add more method if you need to expose the promises.