angular.js view doesn't update - angularjs

I am updating an object within a resource.save callback like so:
$scope.addProfile = function () {
User.save( { "id": user_id }, $scope.createdProfile, function( savedUser, getResponseHeaders ) {
//$scope.$apply(function () {
$scope.user = savedUser;
console.debug($scope.user); // I doublechecked that this contains the correct data
//});
});
};
Unfortunately the view isn't updating correctly. As you can see I have already tried to wrap the thing in an apply, which results in an error "Error: $digest already in progress". Therefore i commented that bit out again.
The view bit which doesn't update looks like this:
<h1>{{user.name}}</h1>
{{user.location}}
...
The function addProfile is called from a button inside a form like so:
<form name='profileForm' >
<div class="section">
<label class="title">Name <span class="help">(required)</span>
<textarea ng-model="createdProfile.name" ></textarea>
</label>
</div>
<div class="section">
<button class="btn btn-large highlight" ng-disabled="!profileForm.$valid" ng-click="addProfile()">Save</button>
</div>
</form>
Thanks in advance for any help!

You aren't defining your controller in the html.
<ANY ng-controller="{expression}">
...
</ANY>

Related

How to trigger multiple Click events on one click angular js

I am having different ng-clicks events, I want all those to be triggered at once on click of a button
Example
<div ng-controller="one">
<input type="button" id="one" ng-click="firstBtnClick(a,b)" class="fstClass"/>
</div>
<div ng-controller="two">
<input type="button" id="two" ng-click="SecBtnClick(c,d)" class="SecClass"/>
</div>
<div ng-controller="three">
<input type="button" id="three" ng-click="ThirdBtnClick(e,f)" class="ThirdClass"/>
</div>
Now I want to hit all this click functions on other button
<div ng-controller="final">
<input type="button" id="final" ng-click="finalBtnClick" class="FinalClass"/>
</div>
Final Controller code
$timeout(function () {
angular.element('.fstClass', '.SecClass').triggerHandler('click');
}, 0);
But I am unable to achieve, Any suggestions??
Why do you want to do this in the view? You are calling controller functions with every button click.
So just have a ng-click="everyClick()" and inside this controller
function, call every function you want to call.
So:
$scope.finalBtnClick = function() {
$scope.firstBtnClick();
$scope.SecBtnClick();
$scope.ThirdBtnClick();
}
If the functions are in the same controller you can chain together like this:
<input type="button" id="final" ng-click="firstBtnClick+SecBtnClick+ThirdBtnClick" class="FinalClass"/>
For communication across controllers you can create and inject a shared service to each controller, nest controllers, use $rootscope or use $emit:
function FirstController($scope)
{
$scope.$on('clickFirst', function(event, args) {
firstBtnClick(args)//click first button
});
// another controller or even directive
}
function FinalController($scope)
{
$scope.$emit('clickFirst', args);
}

AngularJS invoke Controller function

sorry for the rather basic question but I am really a beginner developing in AngularJS.
So I have a conteoller like this (like explaned here: https://github.com/johnpapa/angular-styleguide):
(function() {
'use strict';
angular
.module('project.management')
.controller('ManagementController', ManagementController);
function ManagementController() {
var vm = this;
vm.getUsersBySearchString= getUsersBySearchString;
////////////
function getUsersBySearchString(searchString) {
alert('get User By searchstring: ' + searchString);
}
};
})();
Now I have a HTML fragment in my template and I really don't know how to invoke function getUsersBySearchString(searchString). I have tried this one:
<div ng-controller="vm">
<form class="well form-search">
<label>Usersuche:</label>
<input type="text" ng-model="term" class="input-medium search-query" placeholder="Username">
<button type="submit" class="btn" ng-click="getUsersBySearchStringgetUsersBySearchString()">Suchen</button>
</form>
<pre ng-model="result">
{{result}}
</pre>
</div>
but I don't know what to put here
<div ng-controller="vm">
and how to invoke the method.
Thanks a lot for help!
<div ng-controller="vm">
That is incorrect. You have no controller named "vm". Your controller is named ManagementController.
The syntax for your use-case is
<div ng-controller="ManagementController as vm">
And to invoke the function, you would use
ng-click="vm.getUsersBySearchString(term)"
Note that the alias you choose in the HTML has no relationship with the alias you chose for thisin the controller code. You might very well use
<div ng-controller="ManagementController as managementCtrl">
and
ng-click="managementCtrl.getUsersBySearchString(term)"

ngRepeat not updating after model changed

I'm tring to code a little search input to get data from a database using ngResource.
the data are shown in the page with a ng-repeat, but when i do the search and the $scope has been updated, the view is not updated and show old data.
Here is the code:
main.html (active view)
<div ng-controller="searchCtrl as searchCtrl" layout="column">
<form class="form-inline search-form col-md-offset-1">
<div class="form-group col-md-5">
<label class="sr-only" for="search_location">Location</label> <input
id="search_location" type="search" class="form-control"
ng-Autocomplete ng-model="place" placeholder="Location" />
</div>
<div class="form-group col-md-5">
<label class="sr-only" for="search_tags">Tags</label> <input
style="width: 100%;" id="search_tags" type="search"
class="form-control" id="search_tags" placeholder="Tags">
</div>
<div class="col-md-1">
<md-button class="md-fab md-mini" aria-label="Search" ng-click="searchCtrl.search()"> <md-icon class="md-fab-center"
md-font-icon="glyphicon glyphicon-search" style="color: black;"></md-icon>
</md-button>
</div>
</form>
</div>
<div ng-controller="mainCtrl">
<div ng-repeat="evento in eventi" ng-include="'views/components/event_card.html'" class="col-md-3"></div>
</div>
main.js
'use strict';
app.factory('Eventi', function($resource) {
return $resource('/eventsws/events/:location', {location : '#location'}, {
search: {
method: 'GET',
params: {
'location' : "#location"
},
isArray : true
}
})
});
app.controller('mainCtrl', function($scope, Eventi) {
$scope.eventi = Eventi.query();
});
searchbar.js
'use strict';
app.controller('searchCtrl', function($scope, Eventi) {
$scope.place = null;
this.search = function() {
$scope.eventi = Eventi.search({
'location' : $scope.place
});
}
});
when it start it get all the data from the database and display them correctly, when i try to make a search, the $scope.eventi is updated (i can see the new data in $scope.eventi from the debug) but the view still show the old data and never update.
I've tried to use $scope.$apply at the end of the search function but the result is the same.
Have you any idea why it's not working?
Thanks for your time.
The $scope.eventi you see in the debug is the one in your searchCtrl and not the one from your mainCtrl. To update your mainCtrl $scope.eventi you have to find an other way.
A clean but long solution would be using services to shares variables in your controllers.
To answer the question in comments :
i can see it updated, but the view still show the old data
I guess what's the problem (even if i actually didn't see your code).
Problem
If you bind your var like this :
Service
[...]
service.serviceVar = 1;
return service
[...]
This will create a "1" var with a reference.
Controller
[...]
$scope.myvar = Service.serviceVar;
[...]
This will bind $scope.myvar to the "1" reference.
If you do this in your service or in an other controller :
service.serviceVar = 2;
You will create a new var "2" with a new reference and you will assign this reference to service.serviceVar. Badly all your old references to the old 1 var will not update.
Solution
To avoid that do it like this :
Service
[...]
service.servicevar = {};
service.servicevar.value = 1;
return service
[...]
You create an object with a new reference and assign it to servicevar.
You create a var "1" and assign it to servicevar.value.
Controller
[...]
$scope.myvar = Service.servicevar;
[...]
You assign the servicevar reference to your scope var.
view
{{myvar.value}}
You can use the value by using the property of your var.
Updating the var doing this :
service.servicevar.value = 2;
You will create a new var "2" with a new reference and replace the old reference by this one.
BUT this time you keep all your references to servicevar in your controllers.
I hope i was clear and it answer your question.
EDIT :
Try to never ever use $scope.$apply. It's a really bad practice. If you use that to make something works, you should probably find an other to do that (And it will be a great question for Stacks i guess : "Why do i need $apply to solve my problem XXXXX")
rsnorman15 has a good point about your uses of asynchronous calls. Take a look at his answer too.
Here is one of my old plunker using a service to share properties
Just change:
$scope.eventi = Eventi.search({
'location' : $scope.place
});
to
Eventi.search({
'location' : $scope.place
}, function(eventi) {
$scope.eventi = eventi
});
It's an asynchronous call so it must be assigned in the success handler.
Another issue you are running into is your ng-repeat is not contained within the div that searchCtrl is scoped. Update your HTML so that it is contained like so:
<div ng-controller="searchCtrl as searchCtrl" layout="column">
<form class="form-inline search-form col-md-offset-1">
... form stuff
</form>
<div ng-repeat="evento in eventi" ng-include="'views/components/event_card.html'" class="col-md-3"></div>
</div>

angularjs button event not firing when clicked

I'm missing something here in the wiring. When the button is clicked the alert in the method isn't displayed.
<div id="mapFilter" ng-controller="MapsController">
<div>
<h3>{{SelectedCustomer.officeName}}</h3>
<input type="button" ng-click="getProperties()" value="Get Data" />
</div>
<div>
<p>hotel count: {{allHotels.length}}</p>
<p>preferred count: {{preferredHotels.length}}</p>
</div>
</div>
The expected execution point:
$scope.getProperties = function () {
var msg = 'Unable to load Properties: ';
alert("getProperties");
Plunkr:
http://plnkr.co/edit/4eF1Wu4tURysTji0b5kO?p=preview
Thanks!
You have to add the ng-app directive to auto-bootstrap your application:
<body ng-app="main">
You will then get some errors in your plunker that you have to fix first (i.e. load ng-resource, ...)

ng-model doesnt communicate with ng-repeat

I've been working on an app for trainers and I have encountered possibly simple
problem, despite that I dont know how to fix this and I tried many different solutions.
What i've noticed is that it works pretty fine when input is above the list generated by ng-repeat but i want the list to be under the input.
Any suggestions will be appreciated.
Here is the html code as it is now:
<html ng-app="trainingSupport">
<form method="post" enctype="multipart/form-data" action="" ng-controller="addOffer">
<div class="span40"><input type="text" ng-model="newOffers.offerName" name="offer" class='span48 offer-in'></div>
<div class="span8 options-btn">
<div class="pencil-offer"><i class="icon-pencil icon-offer"></i></div>
<button ng-click="newOffer()" type='submit' class="btn save-offer"><i class="icon-save"></i></button>
<button type="submit" class="btn trash-offer"><i class="icon-trash"></i></button>
</div>
</form>
</div>
<div class="row-fluid">
<ol class="span48" ng-controller="addOffer">
<li ng-repeat="offer in offers" ng-bind='offer.offerName' class="unbold f-pt-sans offer-list"></li>
</ol>
</html>
and here is the tha angular code:
var trainingSupport = angular.module('trainingSupport', []);
function addOffer($scope){
$scope.offers=[
{id:0, offerName:"szkolenie z pieczenia indyka"},
{id:1, offerName:"szkolenie z gaszenia wodÄ…"},
{id:2, offerName:"szkolenia z bicia konia"}
];
$scope.newOffer = function(){
$scope.offers.push({
offerName: $scope.newOffers.offerName
});
$scope.newOffers.offerName='';
}
}
trainingSupport.controller("addOffer", addOffer);
I created a jsFiddle for this, and chiseled your code down to the basics, for better readability.
http://jsfiddle.net/yhx8h/1/
I refactored your controller quite a bit, its much cleaner now.
var trainingSupport = angular.module('trainingSupport', []);
trainingSupport.controller("addOfferCtrl",
function AddOfferCtrl($scope){
//this variable is bound to your input
$scope.newOfferName = '';
$scope.offers=[
{id:0, offerName:"szkolenie z pieczenia indyka"},
{id:1, offerName:"szkolenie z gaszenia wodÄ…"},
{id:2, offerName:"szkolenia z bicia konia"}
];
$scope.newOffer = function(){
//handy little method to grab the max id in your array
var newId = Math.max.apply(null,$scope.offers.map(function(item){return item.id}));
//increment the id, and add new entry to the array
$scope.offers.push(
{id: newId + 1, offerName: $scope.newOfferName }
);
};
});
And the HTML:
<div ng-app="trainingSupport" ng-controller="addOfferCtrl">
<input type="text" ng-model="newOfferName" />
<button ng-click="newOffer()" type="button" text="click me to add offer" ></button>
<ol>
<li ng-repeat="offer in offers">{{offer.offerName}}</li>
</ol>
</div>
I bound your input to a separate variable, newOfferName, and got rid of the extra submit button and the <form> tag. Judging from the code you posted, I don't see why you would need to use a <form> tag in this implementation, or a submit button. Instead, you can just bind an ng-click function to a button (or almost any other type of element really) which will handle updating your array and re-binding your list. Finally, I dont see why you need an ng-bind on your <li ng-repeat>, I removed that as well. Hopefully this refactored code helps you out!

Resources