AngularJS updating specific fields with new data - javascript

Say, I have the following code:
<div ng-controller="postsController">
<div id = "post_id_{{post.postid}}" class = "post" ng-repeat="post in posts">
......
<div class="comments">
<div><span>{{post.totalcomments}}</span> Comments</div>
</div>
.......
</div>
</div>
and on page load this evaluates to something like:
<div ng-controller="postsController">
<div id = "post_id_1" class = "post">
......
<div class="comments">
<div><span>3</span> Comments</div>
</div>
.......
</div>
<div id = "post_id_2" class = "post">
......
<div class="comments">
<div><span>6</span> Comments</div>
</div>
.......
</div>
....and so on.....
</div>
How could I then (using a different controller?) update the DOM when there is a change in the post.totalcomments value for a particular post? I've got the backend worked out, and know you can use $timeout to have a controller repeat itself. I would do it with jQuery (messy but easy) like this (eg: post #1 had a new comment):
var newtotal = 4; //but really get the value from ajax call
$("#post_id_1 .comments span").html(newtotal)
But how would I do this with Angular? I don't want to re-display all the posts and the data, every time I check for updated with the server. Just have a controller (which refreshes with $timeout) and only update the changed fields as needed.
Thanks

If you want to refresh the data periodically use $interval rather than timeout, If its going to be only once after a certain perios say 10 seconds use $timeout. And you need not write a separate controller for this. This can be done within the same controller.
A simple interval demo for you,
Sample Demo: http://plnkr.co/edit/fj6crcHkxm6rkwJT9eGg?p=preview
JS:
app.controller('MainCtrl1', function($scope, $timeout, $http, $interval) {
$scope.comments = [{
total: 3,
comment: 'some comment 1'
}, {
total: 10,
comment: 'some other comment'
}];
$interval(function(){
//logic to update comments
$scope.comments[0].total++;
},1000);
$scope.updateCount = function(){
$scope.comments[1].total++;
};
});

Related

Event in Angular Controller Only Fires Once

I'm trying to implement an Angular version of an autocomplete textbox. I found some working examples, but none seem to exhibit the behavior I'm getting.
The autocomplete functionality itself works fine. When a suggested item is selected, the control correctly handles the selection. Subsequent uses of the control (typing in the autocomplete box, making a selection) fail to engage the 'selected' event/condition, although the autocomplete bit continues to work.
Here's my module & controller:
var app = angular.module('myapp', ['angucomplete-alt']); //add angucomplete-alt dependency in app
app.controller('AutoCompleteController', ['$scope', '$http', function ($scope, $http) {
//reset users
$scope.Users = [];
$scope.SelectedUser = null;
//get data from the database
$http({
method: 'GET',
url: '/UserRoleAdministration/Autocomplete'
}).then(function (data) {
$scope.Users = data.data;
}, function () {
alert('Error');
})
//to fire when selection made
$scope.SelectedUser = function (selected) {
if (selected) {
$scope.SelectedUser = selected.originalObject;
}
}
}]);
I'm guessing the problem is in there, but I don't know what it is. I include the bit from my view below, although there doesn't seem to be much there to fuss with:
<div class="form-group">
<div ng-app="myapp" ng-controller="AutoCompleteController">
<div angucomplete-alt id="txtAutocomplete" pause="0" selected-object="SelectedUser" local-data="Users" search-fields="RegularName" placeholder="People Search" title-field="RegularName" minlength="2" input-class="form-control" match-class="highlight"></div>
<!--display selected user-->
<br /><br />
<div class="panel panel-default" id="panelResults">
<div class="panel-heading"><h3 class="panel-title">Manage Roles for {{SelectedUser.RegularName}}</h3></div>
<div class="panel-body">
<div class="row">
<div class="col-md-2">
<img src="~/Images/avatar_blank.png" width="100%" />
</div>
<div class="col-md-4">
<div class="row">
<div class="col-md-4">Selected User:</div> <div class="col-md-6">{{SelectedUser.RegularName}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
Any help would be appreciated!
UPDATE
After fixing the mistake Yaser pointed out, I wasn't getting any information regarding the selected object. So I set the page to output the entire object, rather than the specified fields, and I noticed I was getting information about the selected object, and on subsequent attempts as well.
So this worked: {{SelectedUser}}
This did not: {{SelectedUser.Department}}
Then I looked at the object and noticed its format. It had "title" and "description", and description had inside it the key/value pairs.
So now this works: {{SelectedUser.description.Department}}
And that's it.
Because the first time you are setting $scope.SelectedUser as a function but inside that you are rewriting the same one with an object. so next time it is not a function any more, try to rename the function:
$scope.setUser = function (selected) {
if (selected) {
$scope.SelectedUser = selected.originalObject;
}
}

Strange binding permanence between controllers

I've got a project in which you write a note in a formulary. Then, you submit that note into an information container (now it's just an array for testing purposes, but it's intended to be a DB later).
The formulary has the following controller:
app.controller('controlFormulario', ['$scope', 'SubmitService', function($scope, submitService) {
$scope.formData = {
"titulo":"",
"texto":"",
"fecha": new Date()
};
$scope.submit = function() {
var temp = $scope.formData;
submitService.prepForBroadcast(temp);
}
// more things we don't need now
... which is bound to this part of the DOM, which is added into it, via a directive:
<form ng-controller="controlFormulario as formCtrl">
<div class="element">
<div class="form-group" ng-class="{'has-error': formData.titulo.length > 50 }">
<label for="inputTitulo">Título</label>
<input type="titulo" class="form-control" id="inputTitulo" ng-model="formData.titulo">
<span ng-show="formData.titulo.length > 50" id="helpBlock" class="help-block">El título no puede exceder los 50 caracteres.</span>
</div>
<div class="form-group">
<label for="inputTexto">Texto</label>
<textarea class="form-control" id="inputTexto" ng-model="formData.texto"></textarea>
</div>
<div class="form-group">
<label for="fecha">Fecha</label>
<input type="fecha" class="form-control" id="fecha" ng-model="formData.fecha" disabled>
</div>
<div class="form-group" >
<button class="btn btn-primary" style="height:35px;width:100px;float:right;" id="submit"
ng-disabled="isDisabled()" ng-click="submit()">
Enviar
</button>
</div>
</div>
<div class="note" ng-show="formData.titulo.length > 0">
<div class="title" ng-model="formData.titulo" class="title">{{formData.titulo | limitTo:50}}</div>
<div class="text" ng-model="formData.texto" class="text">{{formData.texto}}</div>
<div class="date" ng-model="formData.fecha" class="date">{{formData.fecha | date}}</div>
</div>
</form>
This is my directive (I don't think it's really needed, but just in case):
app.directive('formulario', [function() {
return {
restrict: 'E', // C: class, E: element, M: comments, A: attributes
templateUrl: 'modules/formulario.html',
};
}]);
I use a service for passing the data between the previous controller, and the note controller (which controls the note objects of the array). This is the service:
app.factory('SubmitService', function($rootScope) {
var data = {};
data.prepForBroadcast = function(recvData) {
data.data = recvData;
this.broadcastItem();
};
data.broadcastItem = function() {
$rootScope.$broadcast('handleBroadcast');
};
return data;
});
... and I receive it in this part of my note controller:
app.controller('noteController', ['$scope', 'SubmitService', function($scope, submitService) {
var nc = this;
$scope.$on('handleBroadcast', function() {
nc.pruebaNota.push(submitService.data);
$scope.formData.titulo = "";
$scope.formData.texto= "";
$scope.formData.fecha = new Date();
});
// more things, the array, etc...
Ok. This should work, and it does, but something strange happens: as you can see, the preview note is binded with ng-model to the form. That works great, ok. But when I submit the form, the new note object keeps bound to the form (so if I delete the form text, the note appears in blank, and if I write something, it gets automatically updated both in the preview note, and the new note), when there isn't any relation between them. The new note, which appears dynamically on the screen, shouldn't be bound to anything.
Am I doing something wrong? Some help would be really nice!
You are forgetting something really important. Memory address. So, the rought idea is something like: imagine that $scope.formData is in the address 123123. You first create a temp var pointing to 123123 then you send it to the service and the service holds the same address 123123 into data.data.
Then in your second controller you say: hey, I want to work with that data.data (AKA your data in 123123) you have SubmitService.
Now when you modify $scope.formData again, you are updating what you have in that 123123 and everything that is "looking" into that address will be updated.
That is the rough idea. To point it simple, you're modifying the same piece of information everywhere.
See it here: http://plnkr.co/edit/zcEDQLHFWxYg4D7FqlmP?p=preview
As a AWolf suggested, to fix this issue, you can use angular.copy like this:
nc.pruebaNota.push(angular.copy(submitService.data));

binding to controller object in Angular

I'm new to angular, trying to bind an an element's content into the controller's Scope to be able to use it within another function:
here is the scenario am working around:
I want the content of the <span> element {{y.facetName}} in
<span ng-model="columnFacetname">{{y.facetName}}</span>
to be sent to the controller an be put in the object $scope.columnFacetname in the controller
Here is a snippet of what I'm working on:
<div ng-repeat="y in x.facetArr|limitTo: limit track by $index ">
<div class="list_items panel-body ">
<button class="ButtonforAccordion" ng-click="ListClicktnColumnFilterfunc(); onServerSideButtonItemsRequested(ListClicktnColumnFilter, myOrderBy)">
<span>{{$index+1}}</span>
<span ng-model="columnFacetname">{{y.facetName}}</span>
<span>{{y.facetValue}}</span>
</button>
</div>
</div>
angular.module('mainModule').controller('MainCtrl', function($scope, $http) {
$scope.columnFacetname = "";
$scope.ListClicktnColumnFilter = "";
$scope.ListClicktnColumnFilterfunc = function() {
$scope.ListClicktnColumnFilter = "\":\'" + $scope.columnFacetname + "\'";
};
}
the problem is that the $scope.ListClicktnColumnFilter doesn't show the $scope.columnFacetname within it, meaning that the $scope.columnFacetname is not well-binded.
In your ng-click instead of calling two different function
ng-click="ListClicktnColumnFilterfunc(); onServerSideButtonItemsRequested(ListClicktnColumnFilter, myOrderBy)"
you can declare like this
ng-click="columnFacetname = y.facetName; onServerSideButtonItemsRequested(columnFacetname , myOrderBy)"
You are trying to pass that model to another function by assigning it to ListClicktnColumnFilter in your controller
By doing in this way, you can achieve the same thing.
I have done one plunker with sample array,
http://embed.plnkr.co/YIwRLWXEOeK8NmYmT6VK/preview
Hope this helps!

AngularJS - Cannot set scope value into template

I have following function:
$scope.setDetailToScope = function(data) {
$scope.$apply(function() {
//$scope.order = data;
$rootScope.order = data;
setTimeout(function() {
$scope.$apply(function() {
//wrapped this within $apply
$scope.order = data[0];
console.log('message:' + $scope.order);
console.log($scope.order);
});
}, 100);
});
};
"
console.log($scope.order);
Gives me values which has been set into scope.
But i cannot get these values in template.
<!-- DEBUG DIV -->
<div class="debugDiv" ng-show="$root.debugable == true">
{{columns}}
</div>
<div data-ng-controller="OrdersCtrl" ng-init="initData()">
<div id="orders_grid" >
</div>
</div>
<!-- GRID TOOLBAR BUTTON TEMPLATE -->
<script id="template" type="text/x-kendo-template">
<a class="k-button" href="\#/orders/create">Add</a>
</script>
<!-- ORDER DETAIL DIV -->
<div class="container" id="orderDetail" data-ng-controller="OrdersCtrl" ng-if="'detailSelected == true'" xmlns="http://www.w3.org/1999/html">
<!-- DEBUG DIV -->
<div class="debugDiv" ng-show="$root.debugable == true">
{{order}} <!--NOT WORKING-->
</div>
If i tried to add values into rootscope it works, but in this case i cannot get value into ng-model.
What i'm doing wrong please?
Many Thanks for any help.
EDIT:
If i tried solution wit $timeout i got on console.log($scope.order);
following object which is not passed into the template:
_events: ObjectacrCrCode: "interlos"actionName: ht.extend.initarchived: falsebaseStationInfo: ht.extend.initbsc: "bsc1"btsRolloutPlan: "plan1"candidate: "B"costCategory: ht.extend.initcreatedBy: ht.extend.initdirty: falsefacility: ht.extend.initid: 3location: ht.extend.initmilestoneSequence: undefinednetworkType: "Fix"note: "poznamka"orderNumber: 111113orderType: ht.extend.initotherInfo: ht.extend.initparent: function (){return e.apply(n||this,r.concat(h.call(arguments)))}partner: ht.extend.initpersonalInfo: ht.extend.initproject: ht.extend.initpsidCode: "psid1"sapSacIrnCode: "sap1"uid: "924c0278-88d0-4255-b8ac-b004155463fa"warehouseInfo: ht.extend.init__proto__: i
well I'm not sure why you are using a setTimeout with scope apply, to me is safer to use a $timeout since it fires another digest cycle,
try something like
$scope.setDetailToScope = function(data) {
$timeout(funtion(){
//$rootScope.order = data; try either data or data[0]
$scope.order = data[0];
},100);
};
please note that calling nested apply methods can run into some problems with the angularjs digest cycle you may get an error like "digest already in progress" so put attention to it.
NOTE:
it seems like you got some dirty data there, so try to do a map between the data and the scope
$scope.order ={};
$scope.order.uid = data.uid;
$scope.order.orderNumber = data.orderNumber //and so on
in your template try something like:
<div class="debugDiv">
<p> {{order.uid}} </p>
<p> {{ order.orderNumber}} </p>
</div>
this could be a little bit rustic but it worth to try it out.

How to add items to a specific dictionary within an item in a list with AngularFire?

The below code shows a list from firebase and shows a corresponding comment field for each item in the list. The user can make a comment on that item and it will update the comment field for that item in the list. Currently, each time a comment is made, it overwrites the previous one, but I'd like for all comments to be saved.
How do I make it so that every time a comment is added, the previous ones are saved as well?
http://jsfiddle.net/chrisguzman/PS9J2/
indx.html
<div ng-app="MyApp" ng-controller="MyCtrl">
<div ng-repeat="(id,item) in data">
<h2>{{item.title}}</h2>
<input ng-model="item.comment"></input>
<button type="submit" ng-click="CommentAdd(id)">Comment</button>
</div>
</div>
app.js
angular.module('MyApp', ['firebase'])
.controller('MyCtrl',
function MyCtrl($scope, $firebase) {
var furl = "https://helloworldtest.firebaseio.com";
var ref = new Firebase(furl);
$scope.data = $firebase(ref);
$scope.CommentAdd = function (id) {
$scope.data.$save(id);
};
});
The following is the data structure within firebase that is generated
{helloworldtest:
{-JSQhsAnY5zhf0oVKfbb: {title: "nameA", comment:"Second Comment"},
-JSQhsAnY5zhf0oVKfbb: {title: "nameB", comment:"Second Comment"}}
}
However, I'd like to create the following where there is a 'comments' branch that holds all comments.
{helloworldtest:
{-JSQhsAnY5zhf0oVKfbb: {title: "nameA", comments:{-JSQhsAnY5zhf0oVKfbb:{Comment:"Second Comment"},-JSQhsAnY5zhf0oVKfbb:{Comment:"First Comment"}}},
{-JSQhsAnYdfdfdffbb: {title: "nameA", comments:{-JSQhsAnY5zhf0oVKfAb:{Comment:"Another Comment"},-JSQhsAnY5zhf0oVKfbb:{Comment:"First Comment"}}}
}
I've tried to do this by replacing
$scope.data.$save(id);
with
$scope.data.$add(id);
I've also tried using :
$scope.data[id].$add({foo: "bar"})
You are saving the comment into a field called comment. Instead, use a list called comments and utilize push or $add.
<div ng-app="MyApp" ng-controller="MyCtrl">
<div ng-repeat="(id,item) in data">
<h2>{{item.title}}</h2>
<input ng-model="newComment"></input>
<button type="submit" ng-click="addComment(id, newComment)">Comment</button>
</div>
</div>
function MyCtrl($scope, $firebase) {
var furl = "https://helloworldtest.firebaseio.com";
var ref = new Firebase(furl+'/items');
$scope.data = $firebase(ref);
var $comments = $firebase( commentsRef );
$scope.addComment = function (id, newComment) {
ref.child(id).child('comments').push(newComment);
};
});
Also Don't nest data just because you can. Instead, consider putting comments in their own path, items in their own path.

Categories

Resources