Update model from inside of another controller - javascript

I am trying to push a new row of data to a table, after submitting the form. However, the table, which is called UrlListCtrl is different from the form, which is UrlFormCtrl.
function UrlFormCtrl($scope, $timeout, UrlService) {
$scope.message = '';
var token = '';
$scope.submitUrl = function(formUrls) {
console.log('Submitting url', formUrls);
if (formUrls !== undefined) {
UrlService.addUrl(formUrls).then(function(response){
$scope.message = 'Created!';
// I need to update the view from here
});
} else {
$scope.message = 'The fields were empty!';
}
}
In UrlFormCtrl, I am sending an array to the database to be stored, afterwards I'd like to update the view, where UrlListCtrl handles it.
function UrlListCtrl($scope, $timeout, UrlService){
UrlService.getUrls().then(function(response){
$scope.urls = response.data;
});
}
I am trying to push the new data to $scope.url. Here is the service:
function UrlService($http) {
return {
addUrl: addUrl,
getUrls: getUrls
}
function addUrl(formUrls) {
console.log('adding url...');
return $http.post('urls/create', {
original_url: formUrls.originalUrl,
redirect_url: formUrls.redirectUrl
});
}
function getUrls() {
return $http.get('urls/get');
}
}
I'm still trying to understand Angular, so this is pretty complicated for me. How can I update $scope.urls from within UrlFormCtrl?

I am not sure that I understand your question completely but I will try to answer it anyways =).
So you are trying to update a variable whose value was changed in another controller?
That is where service can be useful.
Here are the basic steps:
In the service, you have that variable:
myApp.service('ServiceName', ['$http', function(){
var urls = [];
return{
urls: urls
}
}])
Put $watch in one controller, where you want to get that new value:
myApp.controller('FirstController', function(...){
$scope.$watch(function () {
return ServiceName.urls;
}, function (newVal) {
$scope.urls = newVal;
});
})
Then, you change it from another controller:
myApp.controller('SecondController', function(...){
ServiceName.urls.push('newValue');
})
This should do it. $scope.urls will be updated in the first controller even if it was changed in the second.
The concept of $watch may be new to you. So it basically executes a callback function, whenever the first function returns a new value. That is, whenever the variable that is being watched changes.
In your case:
You will have a variable inside your service:
function UrlService($http) {
var urls = [];
function addUrl(formUrls) {
console.log('adding url...');
return $http.post('urls/create', {
original_url: formUrls.originalUrl,
redirect_url: formUrls.redirectUrl
});
}
function getUrls() {
return $http.get('urls/get');
}
return {
addUrl: addUrl,
getUrls: getUrls
urls: urls
}
}
Put a $watch inside UrlListCtrl:
function UrlListCtrl($scope, $timeout, UrlService){
$scope.$watch(function () {
return UrlService.urls;
}, function (newVal) {
$scope.urls = newVal;
});
}
Then, change the value of urls from UrlFormCtrl:
$scope.submitUrl = function(formUrls) {
if (formUrls !== undefined) {
UrlService.addUrl(formUrls).then(function(response){
$scope.message = 'Created!';
UrlService.urls = response['urls'];
});
} else {
$scope.message = 'The fields were empty!';
}
}
The $watch you put inside UrlListCtrl will insure that the new value will be assigned to $scope.urls inside UrlFormCtrl.

Related

How to avoid an AJAX request before getting response for previous call [duplicate]

In angularJS, With one call, when get the service response need access that json value in multiple controllers but in same page
I have two controller js file and both controllers are called in the same page when I called the service "this.getNavigationMenuDetails" in the first controller.js and as well as called in the controller2.js file as well. without timeout function, I want to access that same response which I get it from the "this.getNavigationMenuDetails" service in controller2.js. But it happened that service call twice in the page. I don't want to call the same service twice in a page.
When js are loading that time both controllers are called in the same layer then getting the response from the service so on the second controller2.js file code is not execute after the response. How can I solve this issue so that only one call i can get the response and access this response in controller2.js also.
controler1.js
var app = angular.module("navApp", []);
app.controller("navCtrl", ['$scope', 'topNavService', '$window', function ($scope, $timeout, topNavService, $window) {
$scope.menuItemInfo = {};
/*Navigation Menu new Code */
$scope.getNavigationDetails = function () {
topNavService.getNavigationMenuDetails().then(function (result) {
$scope.menuItemInfo = result;
angular.forEach($scope.menuItemInfo.items, function (val, key) {
if (val.menuTitle ===
$window.sessionStorage.getItem('selectedNavMenu')) {
if ($scope.menuItemInfo.items[key].isEnabled) {
$scope.menuItemInfo.items[key].isActive = 'highlighted';
} else {
$window.sessionStorage.removeItem('selectedNavMenu');
}
}
if (val.menuTitle === 'Find a Fair' && !val.hasSubMenu) {
$scope.menuItemInfo.items[key].redirectTo = appConfig.findafairpageurl;
}
});
});
};
$scope.init = function () {
if ($window.location.pathname.indexOf('all-my-fairs.html') > 0) {
if (angular.isDefined($cookies.get('cpt_bookfair'))) {
$cookies.remove('cpt_bookfair', {
path: '/'
});
}
}
$scope.getNavigationDetails();
$scope.callOnLoad();
};
$scope.init();
}]);
app.service('topNavService', ['$http', '$timeout', '$q'function ($http, $timeout, $q) {
var menuInfo;
this.getNavigationMenuDetails = function () {
if (!menuInfo) {
// If menu is undefined or null populate it from the backend
return $http.get("/etc/designs/scholastic/bookfairs/jcr:content/page/header-ipar/header/c-bar.getMenuDetails.html?id=" + Math.random()).then(function (response) {
menuInfo = response.data;
return menuInfo;
});
} else {
// Otherwise return the cached version
return $q.when(menuInfo);
}
}
}]);
Controller2.js
var app = angular.module('bookResourcePage', []);
app.controller('bookResourceCtrl', ['topNavService', '$scope', function (topNavService, $scope) {
$scope.topInfo = '';
topNavService.getNavigationMenuDetails.then(function success() {
$scope.productId = $scope.topInfo.isLoggedin;
$scope.linkParam = '?productId=' + $scope.productId;
}, function failure() {
console.error("something bad happened");
});
}]);
The service would work better if it cached the HTTP promise instead of the value:
app.service('topNavService', function ($http) {
var menuInfoPromise;
this.getNavigationMenuDetails = function () {
if (!menuInfoPromise) {
// If menu is undefined or null populate it from the backend
menuInfoPromise = $http.get(url);
};
return menuInfoPromise;
};
});
The erroneous approach of caching the value introduces a race condition. If the second controller calls before the data arrives from the server, a service sends a second XHR for the data.
You can do this with following approach.
Service.js
app.service('topNavService', function($http) {
var menuInfoPromise;
var observerList = [];
var inProgress = false;
this.addObserver(callback) {
if (callback) observerList.push(callback);
}
this.notifyObserver() {
observerList.forEach(callback) {
callback();
}
}
this.getNavigationMenuDetails = function() {
if (!menuInfoPromise && !inProgress) {
inProgress = true;
// If menu is undefined or null populate it from the backend
menuInfoPromise = $http.get(url);
this.notifyObserver();
};
return menuInfoPromise;
};
});
You have to make a function in service to add your controller's function on list. then each controller will register their get function on service and call service method to get data. first call will make service variable inProgress to true. so it will prevent for multiple server request. then when data available to service then it will call its notifyObserver function to message for all controller by calling their function.
Controller 1
app.controller('ctrl1', ['service', '$scope', function(service, $scope) {
service.addObserver('getData1'); //name of your controller function
$scope.getData1() {
service.getNavigationMenuDetails.then(function success() {
$scope.productId = $scope.topInfo.isLoggedin;
$scope.linkParam = '?productId=' + $scope.productId;
}, function failure() {
console.error("something bad happened");
});
}
$scope.getData1()
}]);
Controller 2
app.controller('ctrl1', ['service', '$scope', function(service, $scope) {
service.addObserver('getData2'); //name of your controller function
$scope.getData2() {
service.getNavigationMenuDetails.then(function success() {
$scope.productId = $scope.topInfo.isLoggedin;
$scope.linkParam = '?productId=' + $scope.productId;
}, function failure() {
console.error("something bad happened");
});
}
$scope.getData2()
}]);
with this approach you can real time update data to different controllers without have multiple same request to server.

angular get and set atributes via service

i can't find a solution to this, basicly everytime i do a login, i want to store the user that i get from the node end point in the service, after that in my main Controller i should get the name of the user, but that never happen, dunno why
here is the code:
app.controller('MainCtrl', function ($scope, $state,$location,$http,user) {
$scope.user = {
nome: user.getProperty()
};
$scope.showRegister = function () {
$state.go('register');
}
$scope.showLogin = function () {
$state.go('login');
}
});
app.controller('loginController', function ($scope, $http, $state,user) {
$scope.login = function () {
var data = {};
data.password = $scope.loja.password;
data.email = $scope.loja.email;
$http.post('http://localhost:8080/login/',data)
.success(function (data) {
console.log(data);
user.setProperty(data.nome);
$state.go('home');
})
.error(function (statusText) {
console.log("failed");
});
}
});
user service
app.service('user', function () {
var property = {};
return {
getProperty: function () {
return property.nome;
},
setProperty: function (value) {
property.nome = value;
}
};
});
You could just watch your service for changes by adding this code to your MainCtrl:
$scope.$watch(function () { return user.getProperty();}, updateProp, true);
function updateProp(newValue, oldValue) {
$scope.user = {
nome: newValue
};
}
updateProp gets executed everytime the value of user.getProperty() changes.
Your main issue is with your MainCtrl . In the initial execution of MainCtrl there is no value set into your service so its get blank. MainCtrl executes before setting the value in the service.
$scope.user = {
nome: user.getProperty()
};
this code should be executed after setting the value in the service but it executes in the initialization of controller.
You can get the reference from the fiddle below.
http://jsfiddle.net/ADukg/9799/

Get an element by id with Angular service

I have a service to get (with array) all post from a server. I need to filter this array by id and show only this post in a single page.
In the service I have this code.
.service('PostAPI', function($http) {
this.getAll = function() {
return $http.get("ajax/getAllPosts.php");
}
this.getOne = function(data) {
return $http.get("ajax/searchPost.php?postID=" + data);
}
this.delete = function(data) {
if (confirm("Are you sure to delete this line?")) {
return $http.delete("ajax/deletePost.php?postID=" + data);
}
}
this.update = function(data) {
return $http.put("ajax/updatePost.php?postID" + data);
}
this.create = function() {
return $http.post("ajax/addPost.php");
}
})
In the controller
.controller("PostControlador", function($scope, $routeParams, PostAPI) {
GetPost();
$scope.title = "Editar post";
function GetPost() {
PostAPI.getOne($routeParams.id).success(function(data) {
$scope.post = data;
console.log($scope.post);
});
};
In post HTML I have this.
<div>
<div>{{post.TASK}}</div>
<div>{{post.STATUS}}</div>
<b>Back</b>
</div>
I'm not able to get any data to show in the page, and also, i have no errors in my console. ¿Any idea?
Check your ajax/searchPost.php?postID= api that is this api returning single object or array, If this api returning object than it should work but If you getting array of single element in response of api then in your api success code use first element of array by data[0].
Controller code
.controller("PostControlador", function($scope, $routeParams, PostAPI) {
GetPost();
$scope.title = "Editar post";
function GetPost() {
PostAPI.getOne($routeParams.id).success(function(data) {
$scope.post = data[0];
console.log($scope.post);
});
};
use then instaed of success. .then returns a promise so that you can handle the asynchrounous calls.
Also you are calling the getPost() method before function definition. So it may not get the promise.
call your getPost(), method after the function definition and check, so that it can receive the promise.
.controller("PostControlador", function($scope, $routeParams, PostAPI) {
$scope.title = "Editar post";
function GetPost() {
PostAPI.getOne($routeParams.id).then(function(data) {
$scope.post = data[0];
console.log($scope.post);
});
};
GetPost();

Passing $scope variable from Controller to Service

Currently writing a prototype app in Ionic, pretty new to ionic and angular. I've written a small JSON API with about 25 objects in it, I've been able to display the list of them on a page we'll call "Library", I'm trying now to use those list items as links to an individual page for each item we will call a "Lesson". The variable $scope.lessonId is being set properly in the controller but being set as undefined in the service. Is it possible to achieve what I'm trying to, or am I just flat out doing this wrong?
.controller('LibraryLessonCtrl', function($scope, $stateParams, LessonService) {
$scope.lessonId = $stateParams.libraryId;
console.log($scope.lessonId);
LessonService.getLessonId()
.then(function(response){
$scope.lesson = response;
console.log($scope.lesson);
});
})
.service ('LessonService', function($http){
return { getLessonId: function() {
return $http.get('api/postsAPI.json')
.then(function (response, lessonId) {
console.log(lessonId);
for(i=0;i<response.data.length;i++){
if(response.data[i].post_id == lessonId){
return response.data[i];
}
}
});
}
};
})
You have to pass your $scope.lessonId variable to your service call if you like to use the value inside your service.
.controller('LibraryLessonCtrl', function($scope, $stateParams, LessonService) {
$scope.lessonId = $stateParams.libraryId;
console.log($scope.lessonId);
LessonService.getLessonId($scope.lessonId)
.then(function(response){
$scope.lesson = response;
console.log($scope.lesson);
});
}).service ('LessonService', function($http){
return { getLessonId: function(lessonId) {
return $http.get('api/postsAPI.json')
.then(function (response) {
console.log(lessonId);
for(i=0;i<response.data.length;i++){
if(response.data[i].post_id == lessonId){
return response.data[i];
}
}
});
}
};
})
You could do it by passing Id to service and storing it there. Please try not to pass $scope variable to service as it is not a good practice. You can do following:
.service ('LessonService', function($http){
var lessionId;
return {
/*other methods*/
setLessionId: function(id) {
lessionId = id;
},
getLessionId: function(){
return lessionId;
}
};
})

Angular scope items not applies after item change

I have items service,items list controller, and item details controller:
.state('dashboard.items', {
url: '/items',
templateUrl: '/js/components/dashboard/items/items.html',
controller:'itemsListCtrl'
})
.state('dashboard.items.details', {
url: '/:id',
templateUrl: '/js/components/dashboard/items/itemDetails.html',
controller: 'itemDetailsCtrl',
resolve:{
items: function (ItemService) {
if(!ItemService.items)
ItemService.getAll().then(function (res) {
ItemService.items = res.data;
});
}
}
})
app.factory('ItemService', function ($http) {
var itemsFactory = {};
itemsFactory.getAll = function () {
return $http.get('/items');
}
itemsFactory.update = function () {
itemsFactory.items[0].name = "sadasd";
}
return itemsFactory;
})
app.controller('itemsListCtrl', function($scope, $state, ItemService){
if(!ItemService.items) {
ItemService.getAll().then(function (res) {
ItemService.items = res.data;
$scope.items = ItemService.items;
});
}else{
$scope.items = ItemService.items;
}
})
app.controller('itemDetailsCtrl', function ($scope, items, ItemService) {
$scope.item = ItemService.items[0];
$scope.item.name = "abc" ;
$scope.update = function(){
ItemService.update();
}
})
I have ng-click button which invokes the edit() function.
I made it simple for the example, when doing the update, and edit the item name, the item that presents in the list doesnt change.
I dont know what I miss here. The list sits in the service, and both controllers use it for their purposes.
What am I doing wrong? What is best practice for this scenario?
Update 1
Found something weird. When I edit the item in the controller initialization, it changes the original value globally. When it happens via the edit() method, it doesn't. What happnes?
Thanks.
$http.get returns a promise that it will return your data, so in .then you can do your stuff and it will execute when done(async)
$http.get('/items').then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
return response.data;//this is your data
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});

Categories

Resources