I'm new to angularJS and have a question about caching etc.
I have a wizard with two steps, I want to be able to click back and next and have the forms still filled out as the user had them.
In my page1Partial i have this:
<li ng-repeat="pick in picks | orderBy:orderProperty">
<b><span ng-bind="pick.name"/></b>
<input type="checkbox" ng-model="pick.checked" ng-click="updateBasket(pick)">
</li>
When i go to the next page, then click back the checkboxs are cleared, and its because my RESful call to a java service is called again. How can I cache this response?
From my controller, this hits my REST web service every time.
$scope.picks = Pick.query();
My service
angular.module('picksService', ['ngResource']).
factory('Pick', function ($resource) {
return $resource('rest/picks/:id', {}, {
'save': {method: 'PUT'}
});
});
Since 1.1.2 (commit), all the $httpConfig options are directly exposed in $resource action objects:
return {
Things: $resource('url/to/:thing', {}, {
list : {
method : 'GET',
cache : true
}
})
};
if you replace $resource with $http then you can directly use below code
$http({
method: 'PUT',
url: 'url',
cache:true
});
Related
I inherited a mess. And I need a quick fix for some code that needs to be completely rewritten - but not enough time to do a complete rewrite yet.
Orig developer created an index.js file that has all kinds of global functions used all through an AngularJS/Ionic project. Quite often I am finding AngularJS functions in specific controllers actually passing $scope/$q out to the standard JS functions in the index.js file - its a mess.
One of these global functions is window.FirebasePlugin.onNotificationOpen - which is watching for any inbound pushNotification/messages. The original developer was simply using an "alert" for inbound messages with a data payload. We are now trying to redirect those messages to open up in proper popover or modal windows that belong in the controller in two specific pages.
So the question is, in the global watch JS function, how can I direct
the 'data/payload' to a controller to process in a proper $scope?
I have modified the .state to accept parameters - and then all the subsequent code is in place to pass the $stateParams into specific controllers:
.state('tab.clubs', {
cache: true,
url: '/clubs',
views: {
'tab-clubs': {
templateUrl: 'templates/tab-clubs.html',
controller: 'ClubCtrl',
params: {
'pushAction' : 0,
'pushCode' : 'default'
}
}
}
})
The problem I am having is trying to figure out how to pass URL data from standard JS into the AngularJS .state
The global JS function:
window.FirebasePlugin.onNotificationOpen(function(payload) {
// if there is a payload it will be in payload object
if (payload.action == 1) {
window.location("/clubs/", payload) ; // process message in ClubCtrl
} else if (payload.action == 2) {
window.location("/map/", payload) ; // process message in MapCtrl
}
}, function(error) {
console.error(error);
}) ;
But this method fails.
If your not going to use angulars router to navigate to the page you will need to declare the params in the URL somehow. You can use path params by doing something like /clubs/:pushAction/:pushCode or url params with something like /clubs?pushAction&pushCode
Example:
.state('tab.clubs', {
cache: true,
url: '/clubs/:pushAction/:pushCode',
views: {
'tab-clubs': {
templateUrl: 'templates/tab-clubs.html',
controller: 'ClubCtrl',
params: {
'pushAction' : 0,
'pushCode' : 'default'
}
}
}
})
Then navigate it with
location.href = `/clubs/${payload.action}/${payload.code}`
Additionally if you have alot of unknown params you could also pass in the whole payload as base64 encoded json. I wouldnt recommend this but it is... a solution
.state('tab.clubs', {
cache: true,
url: '/clubs?state',
views: {
'tab-clubs': {
templateUrl: 'templates/tab-clubs.html',
controller: 'ClubCtrl',
params: {
'state' : 0,
}
}
}
})
window.location(`/clubs?state=${btoa(JSON.stringify(payload))}`
Then in your controller reverse that operation
class ClubCtrl {
...
// parses the state out of the state params and gives you the full payload
parseState($stateParams) {
return JSON.parse(atob($stateParams.state));
}
...
}
It would give you all the payload, but its pretty gross
I am designing UI for a REST based server side application developed using Jersey API. I want to take inputs from HTML form and pass the data as query string parameters to build the REST URL. I went through the AngularJS documentation too but didn't find the answer to my question. I came to know that $resource is used for GET/POST/PUT requests and I know that we can build URL with query strings using $resource. Can anyone guide me on how to pass the query string parameters from form fields?
Create an input field in HTML and button to add data
<div ng-controller="myCtrl">
<input ng-model="item.name" />
<button ng-click="addItem()">Add Item</button>
</div>
Create a Service for calling API
var myApp = angular.module("myApp",['ngResource'])
myApp.factory("myService", function ($resource) {
return $resource(
"http://localhost/items/:id",
{id: '#id'},
{
update: { method: 'PUT' },
query: {method: 'GET', isArray: true},
get: {method: 'GET'}
}
)
})
Create a Controller
myApp.controller("myCtrl", function ($scope, myService) {
$scope.Details = myService.get();
$scope.addItem = function () {
myService.save($scope.item, function (data) {
$scope.Details.push(data);
$scope.item = {};
});
};
I currently have a factory that looks like this:
ChecklistApp.factory('Api', ['$resource', function ($resource) {
return {
Checklists: $resource('api/checklists', {}, { 'query': { method: 'GET', isArray: false } }),
Checklist: $resource('api/checklist', {}, { 'query': { method: 'GET', isArray: false } }),
AddChecklist: $resource('api/addchecklist', {}, { 'query': { method: 'POST' } }),
UpdateChecklist: $resource('api/updatechecklist', {}, { 'query': { method: 'PUT' } })
};
}]);
I have two controllers that use this factory
a list controller - which lists all checklists
an update controller - which displays one checklist and allows its detailed to be modified
The list controller assigns the data to a variable which in turn is bound to the UI as follows:
$scope.search = function () {
Api.Checklists.query({ Name: $scope.searchName },
function (data) {
$scope.checklists = data.checklists;
}
);
};
In my edit controller I have the following update function which successfully updates the data in the DB and returns the user to the home (list) page.
var EditCtrl = function ($scope, $location, $routeParams, Api) {
$scope.action = "Update";
var id = $routeParams.editId.replace(/\D+/, '');
Api.Checklist.query({ id: id },
function (qd) { $scope.item = qd.checklist; }
);
$scope.update = function () {
Api.UpdateChecklist.save({ Id: $scope.item.id, Name: $scope.item.name },
function (data) {
$scope.item = data.checklist[0];
$scope.$apply();
$location.path('/#'); //Return to list controller
}
);
}
My issue is that after data is modified in my edit controller, I navigate back to the list control and although it hits the search query in the javascript it does not hit the service endpoint on the second call (skips it altogether) and the data is not refreshed (so the modified checklist has been updated on the DB but in the view on list control is remains as it was).
So my question is
How can I forcefully load the data again from the db using the same query that was run to load data initially ($scope.search in list control >> why does it skip this when the page is navigated to for the second time?) and/or alternatively is there a better way to just share the collection over multiple controllers (I read about nesting the scopes and putting the collection in the parent scope which could be accessed by both controllers but not sure if this is best practice or a suitable solution?)
Thanks
I'm setting up a project using django-tastypie REST API and AngularJS. I'm fine with reading things from the json file through angular, but I cannot find a decent tutorial that would show me how to make even a simple CRUD application that isn't saving all the information in an object or whatever, but is manipulating the database through the tastypie api. Can any of you show me a tutorial of such sort or maybe just show me some sample code for this?
Thank you.
Use $resource - A factory which creates a resource object that lets you interact with RESTful server-side data sources.
Let's say you have Django model Book, and tastypie resource named BookResource. It's URL is /api/v1/book/. As you know, this URL actually is a resource, that means you can manipulate data in your Book model with GET, POST, DELETE, etc. requests.
You can "map" the Angular $resource to this API resource in a way:
someModule.factory('bookResource', ['$resource', function($resource) {
var apiResourceUrl = "/api/v1/book/:bookId/";
// id - your model instance's id or pk, that is represented in API resource objects.
var resource = $resource(apiResourceUrl, {bookId: '#id'}, {
all: {
method: 'GET', params: {}, // GET params that will included in request.
isArray: true, // Returned object for this action is an array (miltiple instances).
},
get: {
method: 'GET',
},
// [Define custom save method to use PUT instead of POST.][2]
save: {
/* But, the PUT request requires the all fields in object.
Missing fields may cause errors, or be filled in by default values.
It's like a Django form save.
*/
method: 'PUT',
},
// [Tastypie use POST for create new instances][3]
create: {
method: 'POST',
},
delete: {
method: 'DELETE',
},
// Some custom increment action. (/api/v1/books/1/?updateViews)
updateViews: {
method: 'GET',
params: {"updateViews": true},
isArray: false,
},
});
}]);
someModule.controller('bookCtrl', ['$scope', '$routeParams', 'bookResource',
function ($scope, $routeParams, bookResource) {
if ("bookId" in $routeParams) {
// Here is single instance (API's detail request)
var currentBook = bookResource.get({bookId: $routeParams.bookId}, function () {
// When request finished and `currentBook` has data.
// Update scope ($apply is important)
$scope.$apply(function(){
$scope.currentBook = currentBook;
});
// And you can change it in REST way.
currentBook.title = "New title";
currentBook.$save(); // Send PUT request to API that updates the instance
currentBook.$updateViews();
});
}
// Show all books collection on page.
var allBooks = bookResource.all(function () {
$scope.$apply(function(){
$scope.allBooks = allBooks;
});
});
// Create new
var newBook = new bookResource({
title: "AngularJS-Learning",
price: 0,
});
newBook.$save();
}]);
Angular's docs provide more information how to make usage of resource really incredibly.
Here is the problem with urls. As I remember, Angular will send request to /api/v1/books/1 (without slash in the end) and you'll get 404 from tastypie. Let me check this.
[2] http://django-tastypie.readthedocs.org/en/latest/interacting.html#updating-an-existing-resource-put
[3] http://django-tastypie.readthedocs.org/en/latest/interacting.html#creating-a-new-resource-post
First time working with angularjs and my data is loading a little slow. Basically when the user chooses to edit a Task, we are accessing a web service to return the data for the task. In addition, there are 3 dropdowns on the page so we need to access a service to return that data as well.
The page displays, the data for the task fills in, and then one at a time the data for the dropdowns fill in.
How can I wait to display the template until all the data has been loaded? or get the data to load simultaneously?
Here is an example of the code that is getting the data:
$scope.task = Task.get({ id: taskId }, function() {
$scope.vendor.terms = Term.query('', function() {
$scope.vendor.states = State.query();
});
});
Here are the services:
angular.module('App.Services', ['ngResource'])
.factory('Task', function($resource, baseUrl) {
return $resource(baseUrl+'/tasks/:id', {'id': '#id'}, {
});
})
.factory('Vendor', function($resource, baseUrl) {
return $resource(baseUrl+'/vendors/:id', {'id': '#id'}, {
});
})
.factory('Statue', function($resource, baseUrl) {
return $resource(baseUrl+'/states/:id', {'id': '#id'}, {
});
})
You could use resolves.
It's a property that you set on whatever route you want, in your app.js
Basically, it's a list of promises that must be resolved before the controller will instantiate and the view will load.
Check out this video from egghead.io screencasts link