Fairly new to AngularJS and first time posting here. On a data entry page, I display a select list where the options in the list come from an array. The array can have items added which need to be reflected in the select list. I can see the items are being added to the array but the options list is not updating without reloading the entire page.
How does one update or refresh the select options list after it has been initialized?
<select ng-model="VendorsController.selectedVendor.Items.selectedItem.locno"
style="width:300px;"
size="1"
ng-options="opt.value as opt.label for opt in VendorsController.selectedVendor.Locations"
required >
</select>
The new item is saved on the server with a callback and the promiss has the following statement to push the new (Location) item onto the array.
_this.selectedVendor.Locations.push(_this.selectedVendor.Locations.selectedLoc);
The array reflects the new item was pushed correctly but the options list does not show it. Any suggestions?
Here is some additional code about where I call on the push().
this.SaveLocation = function(){
$http.post('cfm/callback4.cfmx', _this.selectedVendor.Locations.selectedLoc ).
success(function (data, status, headers, config) {
// if new location pk now reflects valid data
_this.selectedVendor.Locations.selectedLoc = data;
//console.log(data);
//console.log(status);
//console.log(config);
// add location to list
if (_this.selectedVendor.Locations.addNew) {
_this.selectedVendor.Locations.selectedLoc.value = data.locno
// this push is not showing up on the locations options
_this.selectedVendor.Locations.push(_this.selectedVendor.Locations.selectedLoc);
}
// must reset after promiss is returned
_this.selectedVendor.Locations.originalLoc = undefined;
_this.selectedVendor.Locations.selectedLoc = undefined; // null;
_this.selectedVendor.Locations.addNew = false ;
}).
error(function (data, status, headers, config) {
// log error
console.log(data)
console.log(status)
console.log(config)
});
}; // end SaveLocation
And my form button that calls the above function.
<button ng-show="VendorsController.selectedVendor.Locations.selectedLoc" class="btn btn-default" data-dismiss="modal" ng-click="VendorsController.SaveLocation()">Save</button>
Here is how I create the controller... A friend that understands more about AngularJS suggested I use the _this when I'm calling on properties within functions of the controller... something to do with scope or at least that is the way I understood it.
app.controller('VendorsController', ['$scope', '$window', '$http', '$routeParams', '$location', 'state','$timeout','$upload', function ($scope, $window, $http, $routeParams, $location, state, $timeout,$upload) {
var _this = this; // the controller
this.name = "VendorsController";
this.params = $routeParams;
Related
I'm very new to AngularJS and programming aswell, so it can be easy question for you but I'm struggling with it for plenty of hours and can't get my thinking straight.
So, my goal is simple, to have facebook login on my app (webpage), I'm using Ciul angular-facebook module, this actually works but not in the way I want it. When user loggs I want to show his name and photo, but now I have to manually reload page, then it shows, until then it won't. Also I'm storing logged user into localStorage (works ok).
The problem is that after logging in the data aren't updated. In my html code I tried to call them from controller or service, but both had old data, and I don't know how to update it without reloading the page. The most interesting part is when I try it with simple variable and it works like a charm.
Here is my Service
app.factory('mainService', ['$window', '$location', '$route', '$filter', 'Facebook', function (win, $location, $route, $filter, Facebook) {
var scope = {
fbLogin: false,
fbUid: 0,
fbAccessToken: 0,
vkLogin: false
};
var user = {};
if(localStorage.getItem('user') != null) {
user = JSON.parse(localStorage.getItem('user'));
} else {
user = null;
}
return {
scope : scope,
user : user,
fbLogin : function () {
Facebook.login(function (response) {
scope.fbLogin = response.status;
scope.fbAccessToken = response.authResponse.accessToken;
scope.Uid = response.authResponse.userID;
Facebook.api('/me?fields=id,name,email,picture', function (response) {
localStorage.setItem('user', JSON.stringify(response));
});
});
console.log('setting user');
user = JSON.parse(localStorage.getItem('user'));
},
fbLogout : function () {
Facebook.logout(function (response) {
});
user = null;
localStorage.removeItem('user');
},
removeAuth : function () {
Facebook.api({
method: 'Auth.revokeAuthorization'
}, function (response) {
Facebook.getLoginStatus(function (response) {
scope.fbLogin = response.status;
});
});
}
};
}]);
Here is my Controller
app.controller('IndexController', ['$scope', '$location', '$http', 'mainService', function ($scope, $location, $http, mainService) {
$scope.ms = mainService;
$scope.user = mainService.user;
$http({
method: 'GET',
url: 'backend/api/v1/getItems.php',
headers: { "Content-Type": 'text/json; charset="utf-8"' }
})
.success(function(data, status) {
//alert("status is : "+status);
if(status === 200) {
$scope.items = data;
}
})
.error(function(data, status) {
$scope.items = [];
});
}]);
Calling login function < li >< a href="#/" ng-click="ms.fbLogin()">Login using Facebook
Calling data in html {{user.name}} or {{ms.user.name}}
Well, the same problem is also with logging out.
Hey so it's hard for me to say this is the exact problem but from the looks of it everything you have so far is actually pretty good.
There's only one problem I spot and it just boils down to understanding objects are bound to variables by reference. If you're not sure what that means I would say do some research on that first since it's a fundamental part of javascript.
What seems to be the problem here is that you are setting 'user' to an empty object in your service. In your controller you are then assigning $scope.user to that same object empty.
However in your login function you are assigning user to the new JSON from the storage. First, this should also be inside the success callback, right after you set the localstorage.
I'm not familiar with that module but I'm going to assume that those are async functions. Therefore you're grabbing that local storage data before it's even been set.
Also, by setting 'user' to a new object you have updated it's value in the service but not in the controller.
Because it's bound by reference, 'user' in the service now points to a new object, while $scope.user is still pointing to that original empty object.
To solve this problem you can do two things:
Handle the callback differently so that you reassign $scope.user to the new data.
Or you can take advantage of object reference.
You can keep most of your code the same, but in your service, instead of assigning the data to 'user', assign it to a property on user.
Facebook.api('/me?fields=id,name,email,picture', function (response) {
localStorage.setItem('user', JSON.stringify(response));
user.data = response;
});
Since both the service and the controller are referencing the same object, you will have access to that new data property on $scope.user.
HTML:
<span>{{user.data.name}}</span>
I am newbie for angularjs.I have list of persons and each person have edit and delete button. when i click to edit button ng-dialog box was open and show person details and person can change and save information on database,behind save button ajax call trigger and update information on database.
Updating information on database work well but on UI side my view doesn't reflect my database changes.
I had tried to apply "$scope.$apply();" method but i got error message "$digest already in progress".
Please help me,how can refresh my scope after ajax call.
You can use shared service for that and broadcast any event through this service. Broadcasted event can be listened in any controller with $scope.$on.
For example:
angular.module("app", []).factory("sharedService", function($rootScope){
var mySharedService = {};
mySharedService.values = {};
mySharedService.personWasUpdated = function(){
$rootScope.$broadcast('update');
}
return mySharedService;
});
Ctrl for person editing.
app.controller('personEditController', ['$scope', 'sharedService', '$http', function ($scope, sharedService, $http) {
$scope.updatePerson = function(newPerson){
$http.post("../some URL/..", {person: newPerson})
.success(function(data){
sharedService.personWasUpdated(); //event broadcasing
})
};
}
Ctrl for displaying list of persons.
app.controller('personController', ['$scope', 'sharedService', '$http', function ($scope, sharedService, $http) {
var loadPersonsData = function(){
$http.get("../some URL/..").
.success(function(data){
$scope.persons = data;
})
};
loadPersonsData(); //first load
$scope.$on('update', function () {
loadPersonsData(); // load after update of any person
});
}
Try with $scope.$digest(); or use $http instead jQuery ajax or others
I have an issue when I try to display data.
I send my form and update my database (it works great, backend is ok)
I use a button on the page to return to homepage
The view of the homepage is not updated, always the same values.
(It seems that there is only the template that loads, not with queries)
I need to click on the button refresh of the browser to see new values.
After the 'hard' refresh, the view is updated.
Why do I need to completely refresh the page ?
Here is my code
JS :
My service GenericService
(I created this service because I use this in several controllers)
myApp.factory('GenericService', function ($http, $q, MyFunctions) {
var data = {};
function getDataIfNeeded(action) {
action = action || 'default';
if (data[action] !== undefined) {
return $q.when(data[action]);
}
return $http({
url: "php/functions.php",
method: "GET",
params: {
action: action,
dummy: MyFunctions.randomString(7)
}
}).then(function(response) {
data[action] = response.data;
return data[action];
});
}
return {
getData: getDataIfNeeded
};
});
The call of the service
myApp.controller('listCtrl', ['$scope', '$http', '$rootScope', '$location', 'GenericService',
function ($scope, $http, $rootScope, $location, GenericService) {
GenericService.getData("get_projects").then(function (data) {
$scope.projects = data;
});
GenericService.getData("get_projects_draft").then(function (data) {
$scope.projects_in_draft = data;
});
}]);
HTML :
<div ng-controller="listCtrl">
<div ng-repeat="project in projects">
<span>{{ project.nom }}</span>
</div>
<div ng-repeat="project_draft in projects_in_draft">
<span>{{ project_draft.nom }}</span>
</div>
</div>
Your service GenericService fetch the data from the server only "if needed", which means if the local data variable isn't empty. Naturally, without reloading the service and after a form submission, the data will be out-of-sync! So you have two choices:
If the server is creating additional data, i.e. possesses data that AngularJS don't have after the form submission, you need to do another request in order to fetch the new data. Just empty the local data variable.
Else, if the server is just saving the data in a database for instance, and doesn't perform any other operation with an impact on what is shown on your page, you don't have to do an other request, since you already know what you sent to the server! Just update the local data variable.
I'm just starting to use AngularJS.
I have a simple CRUD app which communicates to REST api. I have two controllers which control my Projects data and Tasks data respectfully. On the backend Tasks are liked by foreign key to the parent Project. So when I delete a Project the associated Tasks are also deleted (this is the functionality I want right now).
So everything works except that when I delete a Project I want to reload the Tasks list. Basically after ConcernService.del('projects/', item) is called I want the Tasks list to be refreshed from the API. I know this should be handled via the ConcernsService, but I'm not sure of the best way.
// --- CONCERNS FACTORY --- //
concernsApp.factory('ConcernService', function ($http, $q) {
var api_url = "/path/to/api/";
var ConcernService = {
list: function (items_url) {
var defer = $q.defer();
$http({method: 'GET', url: api_url + items_url}).
success(function (data, status, headers, config) {
defer.resolve(data);
}).error(function (data, status, headers, config) {
defer.reject(status);
});
return defer.promise;
},
del: function(item_url, obj) {
return $http.delete(api_url + item_url + obj.id + '/');
},
};
return ConcernService;
});
// --- PROJECTS CONTROLLER --- //
concernsApp.controller('ProjectsCtrl', function ($scope, $http, ConcernService) {
// get all projects
$scope.projects = ConcernService.list('projects/');
// assign the delete method to the scope
$scope.deleteItem = function(item) {
ConcernService.del('projects/', item).then(function(){
// reload projects
$scope.projects = ConcernService.list('projects/');
});
};
});
// --- TASKS CONTROLLER --- //
concernsApp.controller('TasksCtrl', function ($scope, $http, ConcernService) {
// get all tasks
$scope.tasks = ConcernService.list('tasks/');
// assign the delete method to the scope
$scope.deleteItem = function(item) {
ConcernService.del('tasks/', item).then(function(){
// reload projects
$scope.tasks = ConcernService.list('tasks/');
});
};
});
Instead of a generic service, you could have a service that is more specific to your project and that service could contains the model (projects and tasks). When it would update internally, the watchers from each controller would trigger and update their data.
When you want to share the model between controllers, the model should be kept in a service and you should use getter and setter to access it.
This acticle use an older version of Angular, but it will explain you how to use the service as your model.
http://onehungrymind.com/angularjs-sticky-notes-pt-1-architecture/
I'm new to angularjs and have been attempting to use the angularui modules to build an accordion. For each accordion header I have a nested tag to which calls my service factory. The service factory returns data according to the id and updates my inner accordion content however it updates it for all of the accordion headers. So in other words, clicking on an accordion header will load the same content for all accordion divs. I would like it to return only to the clicked header. I believe I need more help in understanding the scope of my factory service. So my question is if someone can help me understand how to get my service factory to only update it's caller.
my html:
<accordion close-others="false">
<accordion-group ng-repeat="dept in departments">
<accordion-heading>
<span ng-controller="DeptHeaderCtrl" ng-click="loadEmps(dept.DeptID)">
{{dept.DepartmentName}} ({{dept.DepartmentShortName}})
</span>
</accordion-heading>
<div ng-controller="departmentList">
<div ng-repeat="emp in deptemps">
{{emp.Name_First}}
</div>
</div>
</accordion-group>
angularjs factory service code:
app.factory('DeptFactory', function ($http, $rootScope) {
var sharedDeptEmpList = {};
sharedDeptEmpList.EmpList = '';
sharedDeptEmpList.fetchDeptEmps = function (deptid) {
var dept = { "userid": userid, "deptid": deptid };
$http({ method: 'POST', url: 'api/Fetch/DeptEmployees/', data: dept }).
success(function (data, status, headers, config) {
EmpList = data;
sharedDeptEmpList.broadCastEmpList();
}).
error(function (data, status, headers, config) {
alert('error');
});
};
sharedDeptEmpList.broadCastEmpList = function () {
alert('broadcasting');
$rootScope.$broadcast('handleBroadcast');
};
return sharedDeptEmpList;
});
Angularjs controller that receives broadcast:
app.controller('departmentList', function ($scope, $http, DeptFactory) {
$scope.init = function (p_userid) {
userid = p_userid;
};
$scope.$on('handleBroadcast', function () {
alert('broadcast received');
$scope.deptemps = EmpList;
});
});
Each directive is just some javascript that associates a DOM node with a given scope. The same way you think of the DOM tree, you can think of a "scope tree". On the other hand, services are just singleton objects that can be injected and used anywhere. They have no implicit relationship to the DOM/scope tree.
By injecting $rootScope into your DeptFactory, you are giving it access to the entire scope tree. When you call $broadcast(), you are sending an event throughout the entire tree, beginning at the root, and then propagating outwards to all of the leaf scopes.
I don't see enough of your code to completely understand what's happening, but I'm guessing that you're seeing all of your accordion divs change because they are all receiving your $broadcasted event, and reacting to it the same way. I would suggest you $broadcast some sort of ID value to identify which div you are trying to change. Then, when you handle this event in each accordion, check the ID against the accordion's ID to see it should change or not.
Does this help?