How to enable auto watch angularJs? - angularjs

I'm beginner with angularJs and have, as i think, simple problem with whatching changes in my $scope.
I have an object $scope.tasks which i received from server. It looks like:
{
2: {id: 2, name: 'name1', user: 3},
3: {id: 3, name: 'name2', user: 1},
4: {id: 4, name: 'name3', user: 4},
}
also i have a function which update user in task:
$scope.managePlannedIterationTask = function(taskId, userId) {
var data = {
'taskId' : taskId,
'userId' : userId
};
$http.post("url", data).success(function(data, status) {
$scope.tasks[taskId].user = userId; //#1
});
};
also i have custom function $scope.test();
this function must to be executed after every change of user in tasks, for example after update query and updating at //#1
I tried to use for this goal $watch and $watchCollection:
$scope.$watchCollection('tasks', function () {
$scope.test();
})
But this doesn't help. And now i must to insert $scope.test() in all places when i'm update my $scope.tasks. It's very sad.
How can i do it automatically?

Using watch isn't be good practice to have it in code. I'd say that have an call to test method when you update call gets succeeded.
And inside a success callback of post call do make an another call to get updated tasks list to make your view data properly in sync with server data. Currently you are updating data on client side itself for particular record, that doesn't make sense in data-centric application which is widely used by multiple users. If suppose you have 1000 users which are accessing this application, and while you are updating any record, other users also has updated/added any record on the same page. So that will add inconsistent behavivor inside application. So that's why I'm suggesting you to make one more ajax again to fetch data & to keep your application to look more consistent and accurate. Making an one more ajax call wouldn't take 100ms, which is less cost paid for good reason.
Code
$scope.managePlannedIterationTask = function(taskId, userId) {
var data = {
'taskId' : taskId,
'userId' : userId
};
$http.post("url", data).then(function(response) {
var data = response.data;
$scope.getTasks();
$scope.test();
});
};
$scope.getTasks = function(){
$http.get('getTasksUrl').then(function(response){
$scope.tasks = response.data;
});
}

You can write a directive with watcher and put on models which you want to be watched. But if I understood you correctly you need to update data on your page after successful post request, you can achieve this by firing get request, after successful post, or at worse case scenario you can use route or state reload depending on which router you use.

Related

Ext JS 4.2: Add "Source Call" parameter to all AJAX calls

I have three different areas in my application that can modify hours. They all use the same grid, store, and model (but different instances) and call the same backend controller. I am trying to implement a way to add a parameter to the AJAX calls, so the backend knows which area of the application that the call came from through the use of a parameter to AJAX calls.
I have attempted the following:
(1) Overriding request function in Ext.data.Connection
Ext.data.Connection.override({
request: function(options){
var me = this;
if(!options.params)
options.params = {};
options.params.location = 'location 1';
return me.callOverridden(arguments);
}});
Result: I couldn't figure out a way to find the module that made the call.
(2) Adding the following to the controllers init of the controllers
Ext.Ajax.on('beforerequest', function(conn, options) {
if(!options.params)
options.params = {};
options.params.location = "location 1";
});
Result: Every call was sending the same location even if it was a different area
Considering that you are using the same store but different instances, the easiest way is to use the store methods of synchronization only. You would have to define the proxy on the store, not the model, then you can easily add a special extraParam on every instance:
Ext.define('MyStore', {
extend: 'Ext.data.Store',
proxy: {
type: 'ajax'
url: 'test.json'
}
});
var instance1 = Ext.create('MyStore');
var instance2 = Ext.create('MyStore');
var instance3 = Ext.create('MyStore');
instance1.getProxy().setExtraParam('source', 'instance1');
instance2.getProxy().setExtraParam('source', 'instance2');
instance3.getProxy().setExtraParam('source', 'instance3');
instance1.load();
instance2.load();
instance3.load();
and to sync:
instance1.getAt(0).set('text', 'testinstance1');
instance2.getAt(0).set('text', 'testinstance2');
instance3.getAt(0).set('text', 'testinstance3');
instance1.sync();
instance2.sync();
instance3.sync();
See in action here: https://fiddle.sencha.com/#view/editor&fiddle/2fl4
Open the network tab to see the parameter:

How can I save my data using localStorage in AngularJS?

I am working on a To-Do list app and would like to save data on the local storage of the device, but I can't figure out what it is I need to do.
In my app.js file I have the following code which allows me to add new tasks and to edit them:
.controller('DashCtrl', function($scope, $ionicPopup, $ionicListDelegate) {
$scope.tasks =
[
{title:"Example 1", completed: true},
{title:"Example 2", completed: false},
];
$scope.newTask = function(){
$ionicPopup.prompt({
title:"New Task",
template: "Enter task:",
inputPlaceholder:"Please add your task",
okText:'Create task'
}).then(function(res){
if (res) $scope.tasks.push({title: res, completed: false});
})
};
$scope.edit = function(task){
$scope.data = { response: task.title};
$ionicPopup.prompt({
title: "Edit Task",
scope: $scope
}).then(function(res){
if(res !== undefined) task.title = $scope.data.response;
$ionicListDelegate.closeOptionButtons()
})
};
The data is stored in the scope so I tried the following:
localStorage.setItem(scope));
And my idea is to call this function every time a new task is added, so that the storage is always up to date. But this does not seem to be working, what am I doing wrong?
This is the way to go:
https://github.com/gsklee/ngStorage
"An AngularJS module that makes Web Storage working in the Angular Way. Contains two services: $localStorage and $sessionStorage."
localStoragestores strings. If your data is already a string, a simple
localStorage.setItem($scope.data) should work. If it's a valid JSON, you stringify it and store as before.
localStorage.setItem(JSON.stringify($scope.data))
#Ladmerc would this work?
$scope.newTask = function(){
$ionicPopup.prompt({
title:"New Task",
template: "Enter task:",
inputPlaceholder:"Please add your task",
okText:'Create task'
}).then(function(res){
if (res) $scope.tasks.push({title: res, completed: false});
localStorage.setItem(JSON.stringify($scope.data));
localStorage.setItem($scope.data);
})
};
I think there are multiple issues with your approach, first being that you are trying to save the whole $scope object, you can place a console.log() to see how much data it contains, spoiler alert, a lot. The $scope object can be huge and there is no need to save it, what you want is to save the tasks. As mentioned by others, you also need to stringify your data, because localStorage only accepts strings. Luckily you don't have to solve these issues yourself, I would highly recommend you take a look at localForage, it is a library that:
localForage is a fast and simple storage library for JavaScript.
localForage improves the offline experience of your web app by using
asynchronous storage (IndexedDB or WebSQL) with a simple,
localStorage-like API.
You can find more information about localForage in the documentation and there is also an Angular wrapper available.
In your case, this would be an example of how to use this library:
$localForage.setItem('tasks', $scope.data).then(function() {
console.log("The tasks have been saved!");
});

AngularJS needed 2 clicks to do search action

Im AngularJs newbie:).
But I have 3 components: controller C1 (for entering search input and clicking submit button),controller C2 (for div which will receive results from SearchService and display it) and service searchService for sending some hardocoded results.
THe idea is that after submitting search text, I have to submit it twice. With one submit click, view of ui-router is updated to partial page without results loaded. After second click the results are displayed.
Then next searches are done on search view page, all is ok, one click gives needed data.
How to fix it: I want to change ui-router view and get results from service with one click?
C1 method code (started after submiting searchText)
$scope.searchText = function searchText(text) {
$log.log("Method searchText with text: " + text);
//var parametersObject = {searchText: text, results: assetResults}
$state.go('search');
$log.log("SearchInputBoxController: rootScope Broadcasting message: " + text);
$rootScope.$broadcast('DoSearch', text);
$log.log("SearchInputBoxController finished");
};
C2 method: event handler for event 'DoSearch'
$scope.$on('DoSearch', function (event, data) {
$scope.asset = searchService.search(data);
$scope.searchText = data;
});
searchService code:
Application.Services.factory('SearchService', ['SearchServiceResource', '$q',
function (SearchServiceResource, $q) {
return {
search : function (searchText)
{
var result = [
{id: 'aaaaa', sn:"1234-1234-1234-1235", name:"DCU_name1", type: "DCU", tags: ["tag1", "tag2"]},
{id: 'aaaaa', sn:"1234-1234-1234-1235", name:"DCU_name2", type: "DCU", tags: ["tag1", "tag2"]},
{id: 'aaaaa', sn:"1234-1234-1234-1235", name:"NODE_name1", type: "DCU_Node", tags: ["tag1", "tag2"]}
];
return result;
}
};
}]);
I believe the clicking twice is because the first click is triggering the state change, then the broadcast occurs, and then the state change occurs. The second click, the state doesn't need to change, and the current now unchanged controller gets the broadcast. There are a couple different approaches I can think of (and I would def shy away from rootscope broadcasting):
in your shared service, maintain a search string variable and on your
controller, put watch on that service's variable.
change your route/state settings to include a parameter like /search/:searchTerm and in the controller, look for the state established searchTerm variable and on the controller load see if searchTerm is provided and fire the search. Some more info here
Let me now if you need any help or more specifics on the ideas listed.

Bulk delete using backbone

I have a view which contains list of employees, end user select the employees and delete the employees more than one at ones.
Each row of the list contains a check box. End user select multiple check boxes and press delete button. The selected records need to delete.
MVC controller takes care of the delete part. Signature of the delete method is:
DeleteEmployes(List<int> empIds).
How can I achieve this?
My backbone model is:
var emp = Backbone.Model.extend({
defaults:{
Id:null,
fname:null,
lname:nulll.
}
});
In order to delete all models with one request, you need to extend backbone's collection with a method that sends a HTTP DELETE request to a controller action that uses the 'DeleteEmployes(List empIds)' function. Something like this may do the trick.
Backbone.Collection.prototype.bulk_destroy = function() {
var modelId = function(model) { return model.id };
var ids = this.models.map(modelId);
// Send ajax request (jQuery, xhr, etc) with the ids attached
// Empty the collection after the request
// You may want to include this as a success callback to the ajax request
this.reset();
};
Create a Backbone Collection and loop through it, destroying each model. This will send the DELETE command for each model to the server.
var Employees = new Backbone.Collection([
{ name: 'Employee1' },
{ name: 'Employee2' },
{ name: 'Employee3' },
]);
Employees.each(function(model){
model.destroy();
});

Query Database with Backbone Collection

I need to query the database using a backbone collection. I have no idea how to do this. I assume that I need to set a url somewhere, but I don't know where that is. I apologize that this must be a very basic question, but I took a backbone course on CodeSchool.com and I still don't know where to begin.
This is the code that I have for the collection:
var NewCollection = Backbone.Collection.extend({
//INITIALIZE
initialize: function(){
_.bindAll(this);
// Bind global events
global_event_hub.bind('refresh_collection', this.on_request_refresh_collection);
}
// On refresh collection event
on_request_refresh_collection: function(query_args){
// This is where I am lost. I do not know how to take the "query_args"
// and use them to query the server and refresh the collection <------
}
})
The simple answer is you would define a URL property or function to your Backbone.Collection like so:
initialize: function() {
// Code
},
on_request_refresh_collection: function() {
// Code
},
url: 'myURL/whateverItIs'
OR
url: function() {
return 'moreComplex/' + whateverID + '/orWhatever/' + youWant;
}
After your URL function is defined all you would have to do is run a fetch() on that collection instance and it will use whatever you set your URL to.
EDIT ------- Making Collection Queries
So once you set the URL you can easily make queries using the native fetch() method.
fetch() takes an option called data:{} where you can send to the server your query arguments like so:
userCollection.fetch({
data: {
queryTerms: arrayOfTerms[], // Or whatever you want to send
page: userCollection.page, // Pagination data
length: userCollection.length // How many per page data
// The above are all just examples. You can make up your own data.properties
},
success: function() {
},
error: function() {
}
});
Then on your sever end you'd just want to make sure to get the parameters of your request and voila.

Resources