angular method not firing in controller after service call - javascript

I have a angular service that gets the currentuser object that is resolved as a promise. I have a partial that is filled by an object userdetails which is invoked inside a method call, but unfortunately the method call is not firing when called after the promise is resolved.
.controller('AccountCtrl', [
'$scope', 'userService', '$compile', '$http', 'utility', 'cloudService', function ($scope, userService, $compile, $http, utility, cloudService) {
$scope.userdetails = {};
$scope.downloadPageChk = $scope.paymentHistoryPageChk = $scope.manageGroupsPageChk = "hide";
$scope.getUserAttribute = function (param, x) {
return userService.getAttribute(param, x);
};
cloudService.fetchCurrentUser().then(function (newCurrentuser)
{
if (newCurrentuser)
{
$scope.currentUser = newCurrentuser;
$scope.getUserDetails = function()
{
if (userService && userService.isLoggedIn())
{
$scope.userdetails = JSON.parse(JSON.stringify(currentUser));
}
};
if (newCurrentuser == 'member') {
if (newCurrentuser.features.download) $scope.downloadPageChk = "show";
if (newCurrentuser.features.paymenthistory) $scope.paymentHistoryPageChk = "show";
if (newCurrentuser.group.enabled) $scope.manageGroupsPageChk = "show";
}
}
}
])
partial
<div data-ng-controller="AccountCtrl">
<div data-ng-init="getUserDetails()">
<input type="text" class="form-control pull-left" id="FirstName" name="FirstName" data-placeholder-attr="First Name" data-ng-model="userdetails.firstname" required>
<input type="text" class="form-control pull-left" id="LastName" name="LastName" data-placeholder-attr="Last Name" data-ng-model="userdetails.lastname" required>
</div>
</div>
please do let me know what am I missing. I am banging my head for 10 hours now, if I move user details out if that cloudservice.fetchuser().then() it atleast calls the function, not sure what is happening when i put it inside.
Similar plunk created here
http://plnkr.co/edit/pLAB4VpLU7uhlSibHzXP?p=preview
Thanks

If you only want the data to be initializied - you don't need the $scope.getUserDetails function and the data-ng-init="getUserDetails()".
Angular will execute the service fetchCurrentUser function and will populate $scope.userdetails on loading.
cloudService.fetchCurrentUser().then(function (newCurrentuser)
{
if (newCurrentuser)
{
$scope.currentUser = newCurrentuser;
if (userService && userService.isLoggedIn())
{
$scope.userdetails = JSON.parse(JSON.stringify($scope.currentUser));
}
if (newCurrentuser == 'member') {
if (newCurrentuser.features.download) $scope.downloadPageChk = "show";
if (newCurrentuser.features.paymenthistory) $scope.paymentHistoryPageChk = "show";
if (newCurrentuser.group.enabled) $scope.manageGroupsPageChk = "show";
}
}
}
}
See plunker.
EDIT:
If you want the getUserDetails function to still be triggerable after initialization you should put it outside the service method:
$scope.getUserDetails = function(){
if (userService && userService.isLoggedIn()){
$scope.userdetails = JSON.parse(JSON.stringify($scope.currentUser));
}
};
And trigger it however you want (via ng-click="getUserDetails()" from the view or $scope.getUserDetails() from the controller).

You should move the function outside the cloudservice.fetchuser().then() method. The getUserDetails method is not available to the $scope object until you call cloudservice.fetchuser().then(). But you do not do this in your partial.
.controller('AccountCtrl', [
'$scope', 'userService', '$compile', '$http', 'utility', 'cloudService',
function ($scope, userService, $compile, $http, utility, cloudService) {
$scope.userdetails = {};
$scope.getUserDetails = function(service, user) {
if (service && service.isLoggedIn()) {
$scope.userdetails = JSON.parse(JSON.stringify(user));
}
};
$scope.downloadPageChk = $scope.paymentHistoryPageChk = $scope.manageGroupsPageChk = "hide";
$scope.getUserAttribute = function (param, x) {
return userService.getAttribute(param, x);
};
cloudService.fetchCurrentUser().then(function (newCurrentuser) {
if (newCurrentuser) {
$scope.currentUser = newCurrentuser;
$scope.getUserDetails(userService, newCurrentuser);
if (newCurrentuser == 'member') {
if (newCurrentuser.features.download) $scope.downloadPageChk = "show";
if (newCurrentuser.features.paymenthistory) $scope.paymentHistoryPageChk = "show";
if (newCurrentuser.group.enabled) $scope.manageGroupsPageChk = "show";
}
}
});
});
]);

I don't see any use of ng-init directive and $scope.getUserDetails method, angular two way data binding will handle the promises. I have updated the plunker for same. http://plnkr.co/edit/IzjNqpdk0zvnHYyCnKJi?p=preview

You are running ng-init before $scope.getUserDetails has been added to $scope, because that only happens in the callback, and that's why you are having the problems.
i think you may be following some of the basic examples a little too closely. As you are getting data asynchronously you don't need ng-init
You let you controller ask the service to download the data, and when it has arrived you assign it to $scope.getUserDetails and angular will put it on the screen.
You can see the updated plnkr
Let me know if I'm missing something significant

Related

ng-change is not firing when changing value from service

I need to reflect some changes to controller B (inside some event) when I make change at controller A. For that I am using a service.
When I am changing service value from FirstCtrl, ng-change is not firing at SecondCtrl. Is there anything I have missed or need to change?
Please note that I am using angular 1.5.6. and don't want to use watch or even scope.
Below is my code.
var myApp = angular.module('myApp', []);
myApp.factory('Data', function() {
return {
FirstName: ''
};
});
myApp.controller('FirstCtrl', ['Data',
function(Data) {
var self = this;
debugger
self.changeM = function() {
debugger
Data.FirstName = self.FirstName;
};
}
]);
myApp.controller('SecondCtrl', ['Data',
function(Data) {
var self = this;
self.FirstName = Data;
self.changeM = function() {
alert(1);
};
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="FirstCtrl as c">
<input type="text" ng-model="c.FirstName" data-ng-change="c.changeM()">
<br>Input is : <strong>{{c.FirstName}}</strong>
<div ng-controller="SecondCtrl as c1">
Input should also be here: {{c1.FirstName}}
<input type="text" ng-model="c1.FirstName" data-ng-change="c1.changeM()">
</div>
</div>
<hr>
</div>
As you dont want to use $scope trying modifying the code in order to use $emit and $on feature in angular js to communicate between two controllers. You can refer this link.
var myApp = angular.module('myApp', []);
myApp.factory('Data', function() {
return {
FirstName: ''
};
});
myApp.controller('FirstCtrl', ['Data',
function(Data) {
var self = this;
debugger
self.changeM = function() {
debugger
//Data.FirstName = self.FirstName;
Data.$on('emitData',function(event,args){
Data.FirstName=args.message
document.write(Data.FirstName)
})
};
}
]);
myApp.controller('SecondCtrl', ['Data',
function(Data) {
var self = this;
self.FirstName = Data;
self.changeM = function() {
Data.$emit('emitData',{
message:Data.FirstName
})
};
}
]);
The only way then is to directly copy the reference of the data object within the controller. Note that you don't need ng-change to update the value then.
If you want something else, either wrap the FirstName in a sub object of Data and do the same i did :
Data = {foo:'FirstName'};
Or use $watch since it's the whole purpose of that function.
Here is a working code with copying the Data object in the controller.
var myApp = angular.module('myApp', []);
myApp.factory('Data', function() {
return {
FirstName: ''
};
});
myApp.controller('FirstCtrl', ['Data',
function(Data) {
var self = this;
self.Data=Data;
debugger
self.changeM = function() {
debugger
};
}
]);
myApp.controller('SecondCtrl', ['Data',
function(Data) {
var self = this;
self.Data = Data;
self.changeM = function() {
alert(1);
};
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="FirstCtrl as c">
<input type="text" ng-model="c.Data.FirstName" data-ng-change="c.changeM()">
<br>Input is : <strong>{{c.Data.FirstName}}</strong>
<div ng-controller="SecondCtrl as c1">
Input should also be here: {{c1.Data.FirstName}}
<input type="text" ng-model="c1.Data.FirstName" data-ng-change="c1.changeM()">
</div>
</div>
<hr>
</div>
The only way I know to solve the problem is using watch, unfortunately. (I am new to angular.)
From the ngChange document (https://docs.angularjs.org/api/ng/directive/ngChange):
The ngChange expression is only evaluated when a change in the input value causes a new value to be committed to the model.
It will not be evaluated:
if the value returned from the $parsers transformation pipeline has not changed
if the input has continued to be invalid since the model will stay null
**if the model is changed programmatically and not by a change to the input value**

Unknown Provider with AngularJS

I would like to create a service and a controller in AngualrJS. The problem is I need to access to $scope in my service.
I think the good solution is to put this service in the controller directly but I have no idea how to do it.
This is my HTML :
<div ng-controller="myController">
<input type="text" id="idInput" name="idInput" ng-model="nameModel">
<button class="btn btn-default" ng-click="functionWhenClick()">Execute</button>
</div>
This is my controller :
var variableModuleName = angular.module("nameModule",[]);
variableModuleName.controller('controllerName',function($rootScope,$scope, CommonService) {
$scope.nameModel = '';
$scope.scopeFunctionName = function () {
CommonService.myFunction($scope.nameModel);
};
});
This is my service :
variableModuleName.service('CommonService', ['dataService', function(dataService) {
this.loadData = function(param) {
dataService.getCommitData(param).then(function(res) {
if (res.error) {
$scope.chartData = res.chartData;
}
});
};
this.myFunction = function(concatURL){
this.loadData('URL' + concatURL);
}
}]);
I hope you will can help me.
Thanks.
First of all, You can't/shouldn't use $scope in a service. You can't inject $scope in the service. You can pass $scope as a function's parameter but that's a bad idea. Because, we don't want our service to play with all our $scope variables.
Now, to rewrite your service to return chartData from an async operation using dataService (assuming dataService.getCommitData(param) does have a call to server) , you need to handle the promise well.
var d3DemoApp = angular.module("D3demoApp",[]);
// service. Assuming dataService exists
d3DemoApp.service('CommonService', ['dataService', function(dataService) {
this.loadData = function(param) {
return dataService.getCommitData(param).then(function(res) {
// Should the if condition be res.error or !res.error
if (res.error) {
return res;
}
});
};
this.myFunction = function(parameterItem){
return this.loadData('http://localhost:3412/bubble/' + parameterItem);
console.log("Fonction appellée");
}
}]);
// controller
d3DemoApp.controller('controllerFilterSearch',function($rootScope,$scope, CommonService) {
$scope.searchText = '';
$scope.getSearchText = function () {
CommonService.myFunction($scope.searchText).then(function(res) {
$scope.chartData = res.chartData;
});
};
});
So, in the above code, I am basically returning a promise from this.loadData function. When we call CommonService.myFunction from controller, we get the response in the then resolved callback function and we set the chartData from response to $scope.chartData.
First don't use var d3DemoApp = angular.module("D3demoApp",[]) through your files.
Use angular.module("D3demoApp",[]) once to get your module instantiated and then get the reference of the existing one using angular.module("D3demoApp")
In your plknr :
You forget to include the service file
I don't see any definition of the dataService which is why you have the unknown provider dataServiceProvider error.
There are many ways to do this. My favorite is creating another service which has reference to the scope.
d3DemoApp.service('scopeServer', ['dataService', function(dataService) {
var scope;
return {
scope: function(_scope) {
if (typeof _scope !== 'undefined')
scope = _scope;
return scope;
}
}
}]);
This service maintains a reference to the scope in a singleton an returns it wherever you call scopeService.scope();
You can set the scope in your controller initially.
d3DemoApp.controller('controllerFilterSearch',function($rootScope,$scope, scopeServer) {
scopeServer.scope($scope);
});
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>
<script src="controllerInput.js"></script>
<script src="app.js"></script>
<script src="serviceInput.js"></script> <!-- Include -->
</head>
<body ng-app="D3demoApp" ng-controller="controllerFilterSearch">
<input type="text" id="searchTextBox" name="searchTextBox" ng-model="searchText">
<button class="btn btn-default" ng-click="getSearchText()">Rechercher</button>
</body>
</html>
var d3DemoApp = angular.module("D3demoApp",[]);
d3DemoApp.controller('controllerFilterSearch',function($rootScope,$scope, CommonService) {
$scope.searchText = '';
$scope.getSearchText = function () {
CommonService.myFunction($scope.searchText);
};
});
service
d3DemoApp.service('CommonService', ['dataService', function(dataService) {
this.chartData = '';
this.loadData = function(param) {
dataService.getCommitData(param).then(function(res) {
if (!res.error) {
this.chartData = res.chartData;
}
});
};
this.myFunction = function(parameterItem){
this.loadData('http://localhost:3412/bubble/' + parameterItem);
console.log("Fonction appellée");
}
}]);
controller
var d3DemoApp = angular.module("D3demoApp",[]);
d3DemoApp.controller('controllerFilterSearch',function($rootScope,$scope, CommonService) {
$scope.searchText = '';
$scope.getSearchText = function () {
CommonService.myFunction($scope.searchText);
$scope.searchText = CommonService.chartData;
};
});

Get input value in a variable in Angularjs before submit to call a webapi

I would like to access the input field value inside a variable that could be used in AngularJS so that I could add it to a string with the help of which I could call a rest api.
kindly help.
<body ng-app="myApp">
<div ng-controller="myCtr">
<form name="myForm">
<input type="text" ng-model='pinCode' id="zip" onBlur="myZipcode">
{{city}}
{{state}}
</form>
</div>
<script>
var zip;
var pat1;
function myZipcode(){
zip = document.getElementById("zip").value;
pat1 = 'http://ziptasticapi.com/'+zip;
}
var myApp = angular.module('myApp' , []);
myApp.controller('myCtr', function($scope, $http){
var path = 'http://ziptasticapi.com/12345'
$http.get(pat1).success(function (response) {
$scope.city = response.city;
$scope.state = response.state;});
});
</script>
</body>
Here in http.get service if I use path variable instead of pat1 it works.
Another thing that I want the state and city to come dynamically without the form to be submitted and to be called from an REST API. That is why I am trying to get the input value inside a variable to accomplish the task
No need to define extra var for pinCode because of you used ng-model so you can access pinCode from your controller. Also should use ng-blur instead of onBlur.
You can use like
HTML:
<input type="text" ng-model='pinCode' id="zip" ng-blur="myZipcode()">
Controller:
var myApp = angular.module('myApp' , []);
myApp.controller('myCtr', function($scope, $http){
$scope.pinCode= ''; // defaulr empty
var path = 'http://ziptasticapi.com/';
$scope. myZipcode = function() {
$http.get(path + $scope.pinCode).success(function (response) {
$scope.city = response.city;
$scope.state = response.state;
});
};
});
You should not access html elements from your controller code. Angular's two way data-binding already transfers the form input's value into the $scope.pinCode variable. So you only need some action to trigger your server call. See this sample in the angular docs: https://docs.angularjs.org/api/ng/directive/ngSubmit
myApp.controller('myCtr', function($scope, $http) {
$scope.doCall = function() {
// $scope.pinCode() is set here
$scope.$http.get(...).then(
function(response) {
$scope.city = response.data.city; // or similar
}
);
}
});
just bind zip and pat1 on controller's scope
Controller:
myApp.controller('myCtr', function($scope, $http){
$scope.zip = document.getElementById("zip").value || 0;
$scope. pat1 = 'http://ziptasticapi.com/'+ $scope.zip || '';
$scope.myZipcode();
});
and then in zipcode
Zipcode function:
$scope.myZipcode = function myZipcode(){
$scope,zip = document.getElementById("zip").value;
$scop.pat1 = 'http://ziptasticapi.com/'+zip;
$http.get(pat1).success(function (response) {
$scope.city = response.city;
$scope.state = response.state;}
}
Complete code:
<body ng-app="myApp">
<div ng-controller="myCtr">
<form name="myForm">
<input type="text" ng-model='pinCode' id="zip" ng-blur="myZipcode">
{{city}}
{{state}}
</form>
</div>
<script>
myApp.controller('myCtr', function($scope, $http){
$scope.zip = document.getElementById("zip").value || 0;
$scope. pat1 = 'http://ziptasticapi.com/'+ $scope.zip || '';
$scope.myZipcode();
$scope.myZipcode = function myZipcode(){
$scope,zip = document.getElementById("zip").value;
$scop.pat1 = 'http://ziptasticapi.com/'+zip;
$http.get(pat1).success(function (response) {
$scope.city = response.city;
$scope.state = response.state;}
}
});
</script>
</body>

AngularJS - To Do App Place Submit and Delete Function into Factories

I've created a simple To Do App and while working on it I felt like I will end up placing too much code into my Controller and will eventually get messy and hard to read. I want to know how can I move my functions into factories so that my code can look somewhat cleaner.
Here is my JS:
angular.module('toDoApp', [])
.controller('toDoCtrl', function($scope){
//set $scope variables
$scope.tasks = [];
$scope.submitTask = function(){
$scope.tasks.unshift($scope.enteredTask);
$scope.enteredTask = '';
};
$scope.removeTask = function(task) {
var i = $scope.tasks.indexOf(task);
$scope.tasks.splice(i, 1);
};
})
.factory('toDoFactory', ['$http', function($http){
return function(newTask) {
};
}])
Here is the HTML if needed:
<form ng-submit="submitTask()">
<!-- task input with submit button -->
<label>Task: </label>
<input type="text" placeholder="Enter Task" ng-model="enteredTask" required>
<button>Submit</button>
</form>
<div>
<!-- create unordered list for task that are submitted
need check boxes -->
<ul>
<li ng-repeat="task in tasks">
{{ task }}
<button ng-click="removeTask()">x</button>
</li>
</ul>
</div>
As you can see I kinda started the factory but just don't know how to go about it.
Any suggestions will be greatly appreciated.
You will need to inject your factory inside controller and then use the methods defined in the factory from the controller:
angular.module('toDoApp', [])
.controller('toDoCtrl', function($scope, toDoFactory){
//set $scope variables
$scope.tasks = [];
$scope.submitTask = function(){
toDofactory.submittask(); //Just for demo.Passin your parameters based on your implementation
};
$scope.removeTask = function(task) {
var i = $scope.tasks.indexOf(task);
$scope.tasks.splice(i, 1);
};
})
.factory('toDoFactory', ['$http', function($http){
var methods = {};
methods.submittask = function(){
//your logic here
};
methods.removetask = function(){
//your logic here
}
return methods;
}])
var app = angular.module('toDoApp', []);
app.controller('toDoCtrl', function($scope, toDoFactory){
$scope.tasks = [];
toDoFactory.get = function(){
}
toDoFactory.delete = function(){
}
toDoFactory.update = function(){
}
});
app.factory('toDoFactory', ['$http', function($http){
var todo = {};
todo.get = function(){
};
todo.delete = function(){
};
todo.update = function(){
}
return todo;
}]);
This is simple architecture, you can add more logic,
Make sure you know about dependency injection(DI)
Here is the answer for those that want to see what the end result will look like when all the code is plugged in. Thanks again for the answers as it was able to guide me in the right direction.
.controller('toDoCtrl', function($scope, toDoFactory){
$scope.tasks = toDoFactory.tasks;
$scope.submitTask = function(){
toDoFactory.submitTask($scope.enteredTask);
$scope.enteredTask = '';
};
$scope.removeTask = function(task) {
toDoFactory.removeTask();
};
})
.factory('toDoFactory', ['$http', function($http){
var toDo = {
tasks: [],
enteredTask: '',
submitTask: function(task){
toDo.tasks.unshift(task);
},
removeTask: function(task) {
var i = toDo.tasks.indexOf(task);
toDo.tasks.splice(i, 1);
}
};
}])

alternative method instead $watch in angularjs

I have a scope variable, when it returns true, i need to trigger some events or do something. I my case, the every first time, the scope variable returns undefined and later it returns true. In this case i used $watch method to get the expected funcionality. Is there any alternative approach to do the same instead using $watch ?
scope.$watch () ->
scope.initiateChild
, (value) ->
if value is true
$timeout ->
scope.buildOnboarding()
, 1000
You can try using AngularJS $on(), $emit() and $broadcast().
Here is an example: http://www.binaryintellect.net/articles/5d8be0b6-e294-457e-82b0-ba7cc10cae0e.aspx
You can use JavaScript getters and setters without any expense of using $watch.
Write code in the setter to do what you want when angular changes the your model's value you are using in scope. It gets null or an a State object as user types. Useful for working with type ahead text boxes that have dependencies on each other. Like list of counties after typing state without user selecting anything.
Here is some pseudo style code to get the idea.
<input ng-model="searchStuff.stateSearchText" />
<div>{{searchStuff.stateObject.counties.length}}</div>
<div>{{searchStuff.stateObject.population}}</div>
$scope.searchStuff=new function(){var me=this;};
$scope.searchStuff.stateObject = null;
$scope.searchStuff.getStateObjectFromSearchText = function(search){
// get set object from search then
return stateObject;
};
$scope.searchStuff._stateSearchText= "";
Object.defineProperty($scope.searchStuff, 'stateSearchText', {
get: function () {
return me._stateSearchText;
},
set: function (value) {
me,_stateSearchText = value;
me.stateObject = getStateObjectFromSearchText (value);
}
});
See this fiddle: http://jsfiddle.net/simpulton/XqDxG/
Also watch the following video: Communicating Between Controllers
A sample example is given below
Html:
<div ng-controller="ControllerZero">
<input ng-model="message" >
<button ng-click="handleClick(message);">LOG</button>
</div>
<div ng-controller="ControllerOne">
<input ng-model="message" >
</div>
<div ng-controller="ControllerTwo">
<input ng-model="message" >
</div>
javascript:
var myModule = angular.module('myModule', []);
myModule.factory('mySharedService', function($rootScope) {
var sharedService = {};
sharedService.message = '';
sharedService.prepForBroadcast = function(msg) {
this.message = msg;
this.broadcastItem();
};
sharedService.broadcastItem = function() {
$rootScope.$broadcast('handleBroadcast');
};
return sharedService;
});
function ControllerZero($scope, sharedService) {
$scope.handleClick = function(msg) {
sharedService.prepForBroadcast(msg);
};
$scope.$on('handleBroadcast', function() {
$scope.message = sharedService.message;
});
}
function ControllerOne($scope, sharedService) {
$scope.$on('handleBroadcast', function() {
$scope.message = 'ONE: ' + sharedService.message;
});
}
function ControllerTwo($scope, sharedService) {
$scope.$on('handleBroadcast', function() {
$scope.message = 'TWO: ' + sharedService.message;
});
}
ControllerZero.$inject = ['$scope', 'mySharedService'];
ControllerOne.$inject = ['$scope', 'mySharedService'];
ControllerTwo.$inject = ['$scope', 'mySharedService'];

Categories

Resources