Why ng-repeate object not getting updated? - angularjs

This is the function which load listings from server. Initially listings are displayed but when gets null response on applying filter, it still shows previous result and not clearing previous listings.
$scope.browseListing = function (strURL) {
$scope.CurrentTab = strURL;
$scope.getURL(strURL);
$http.post($scope.URL)
.then(function (response) {
if (response.data != 'null') {
$scope.Data = response.data;
$scope.TotalListingCount = $scope.Data.length;
$window.alert('Result is not null');
}
else {
$scope.TotalListingCount = '0';
$window.alert('Result is null');
$scope.Data = [];
}
}, function (response) {
$log.info(response);
});
};
Edited
How do I solve this so that on empty response previous listings gets cleared and shows no listings?

May be your scope does not update. Please try this below ( it's not 100% good approach, But at this time you can solve your issue)
if(!$scope.$$phase) {
$scope.$apply(
$scope.Data = [];
);
}
$scope.TotalListingCount = '0';
$window.alert('Result is null');
and please check your console having any error.
Update :
try another way like this (declare empty object globally)
.then(function (response) {
$scope.TotalListingCount = '0';
$scope.Data = [];
if (response.data != 'null') {
$scope.Data = response.data;
$scope.TotalListingCount = $scope.Data.length;
$window.alert('Result is not null');
}
else {
$window.alert('Result is null');
}
}
It's does not works well, then please share your filter code. Bcs the problem should be there.

The following create new scopes, and inherit prototypically: ng-repeat, ng-include, ng-switch, ng-view, ng-controller, directive with scope: true, directive with transclude: true.
So, use $parent with 'ng-repeate' to reference to parent scope instead of using newly created scope byng-repeat` as-
<tr ng-repeat="listing in $parent.Data | orderBy : sortColumn : SortDirection">
After adding $parent in ng-repeat to scope property in UI it updates UI as per changes.
Here is full description of scope

Related

AngularJS - View not updating with new array

I have an array which loads old data on page load.
However, this is not being loaded by angularJS.
It seems my controller is being called twice.
Here's the code
$scope.searchTerms = JSON.parse(APIDataService.loadLocalData('changedSearchTerm'));
var totalPages = JSON.parse(APIDataService.loadLocalData('oldData'));
var getOldDataOn = APIDataService.getOldData($scope.searchTerms, totalPages, 1)
.then(function(data) {
if(data.thumbpath.length > 0)
{
console.log('records found');
$scope.hasResults = true;
$scope.records = data.thumbpath;
} else {
$scope.hasResults = false;
}
},
function(data) {
console.log('Image retrieval failed.')
});
For some reason, console.log($scope.records) shows records, but Angular view is not being updated. I also tried $scope.$apply, but it's not working.
Please help.
Thank you in advance.

why variables keep being empty on factory angular?

services.factory('profilFactory',['$q','$http',function($q,$http){
var factory2 =
{
profils : {},
getProfils : function(){
$dfd = $q.defer();
$http.get('data.json')
.success(function(data,status){
this.profils = data.profil;
$dfd.resolve(this.profils);
})
.error(function(data,status) {
$dfd.reject('erreur recuperation des profils');
});
return $dfd.promise;
},
getProfil : function(idProfil){
var profil={};
var profils = {};
factory2.getProfils().then(function(data){
profils= data;
console.log(profils);//all right until here profils has values
});
console.log(profils);// now profils is empty :\ and the foreach will not execute
angular.forEach(profils, function(value, key){
if(value.id == idProfil){
profil= value;
}
});
return profil;
}
};
return factory2;
}]);
This is a screenshot of the problem : method "getProfil"
To answer your question, "Why are the variables empty in the factory", it's because you are using a console.log statement in a location where the data has not yet been loaded from the server. To learn more, Google this: "angularjs http get promises"
services.factory('profilFactory',['$q','$http',function($q,$http){
var factory2 =
{
profils : {},
getProfils : function(){
$dfd = $q.defer();
$http.get('data.json')
.success(function(data,status){
this.profils = data.profil;
$dfd.resolve(this.profils);
})
.error(function(data,status) {
$dfd.reject('erreur recuperation des profils');
});
return $dfd.promise;
},
getProfil : function(idProfil){
var profil={};
var profils = {};
// Run a function to get data, "THEN" we run a function to process the data:
factory2.getProfils().then(function(data){
// Data has now been loaded so we can process it and return it.
profils = data;
angular.forEach(profils, function(value, key){
if(value.id == idProfil){
profil= value;
}
});
return profil;
});
console.log(profils); // This is EMPTY because it runs immediately after
// the factory2.getProfils() function which may need several seconds to
// load data. That's why "profils" is empty. The data hasn't loaded at
// this point.
//
// No data will be available at this level of the code. Don't try to access
// "profils" here! Only in your .then() function above.
}
};
return factory2;
}]);
Your console.log statement is outside of the callback. That is the issue. You need to console.log in the callback or use a watcher to update it when it gets changed. For future reference you should always copy and paste your code here.

Atmosphere and Angular JS how to

I'm an atmosphere & Angular newbie and I'm really struggling to find an answer to this! Maybe I'm asking the wrong question.
I am setting up notifications using Atmosphere. I can open the websocket and watch the updates happen if I post the API URL directly into my browser.
In Angular I have an ng-repeat loop, which I would like to run as each new update adds a new object to the websocket.
<li ng-repeat="notification in notifications track by $index">
I am using angular watch to check for updates, but it doesn't pick up the new objects being added to the array. Here is my code:
// notification alerts
$scope.notifications = [];
notificationsService.notificationAlerts().then(function success(response) {
var jsonStringArray = response.data.split('|');
$scope.notifications = $.map(jsonStringArray, function(n, i){
if (n !== ""){
return JSON.parse(n);
}
});
console.log('Connect', response);
});
$scope.$watch('notifications', function(newVal, oldVal){
console.log('Watch', $scope.notifications);
}, true);
Hopefully I've made myself clear, let me know if I need to elaborate, or if I'm asking the wrong question. Thanks!
OK, I managed to solve this, for anyone stumbling across it later. Here is the final JS:
// add number of notifications to ".notifications-number"
function updateNumberOfNotifications(){
var numberOfNotifications = $("ul.notifications-list li").not(".nocount").length;
if (numberOfNotifications < 1) {
$(".notifications-number, .notifications-list").addClass("hidden");
} else {
$(".notifications-number").html(numberOfNotifications);
$(".notifications-number, .notifications-list").removeClass("hidden");
}
}
// notification alert variables
$scope.notifications = [];
var socket = atmosphere;
var subSocket;
// subscribe
function subscribe() {
var request = {
url : "/service/notifier",
transport: 'long-polling'
};
request.onMessage = function (response) {
//console.log('response', response);
var jsonStringArray = response.responseBody.split('|');
// console.log('json string array', jsonStringArray);
$.each(jsonStringArray, function(index, elem){
if (elem != ""){
$scope.notifications.push(JSON.parse(elem));
console.log("object", JSON.parse(elem));
}
});
//$scope.notifications.push($scope.newNotification);
$scope.$apply();
updateNumberOfNotifications();
// console.log('$scope.notifications', $scope.notifications);
};
subSocket = socket.subscribe(request);
}
function unsubscribe(){
socket.unsubscribe();
}
// subscribe on load and update notifications
updateNumberOfNotifications();
subscribe();

Can you bind data from one scope to update when another changes in angularJS

My web app depends on one specific variable changing throughout the user's visit. It controls what data the user will see at any given time, essentially akin to a TAG.
If the $scope.tagid = 1, is it possible to have another angular model to instantly update its own dataset when tagid is changed to $scop.tagid = 2?
<script >
function PageCtrl($scope) {
$scope.text = '<?=$tagid?>';
}
$scope.showThread = function(tagid) {
$http({method: 'GET', url: 'api/example/thread/id/' + tagid}).
success(function(data, status, headers, config) {
$scope.appDetail = data; //set view model
$scope.view = './Partials/detail.html'; //set to detail view
}).
error(function(data, status, headers, config) {
$scope.appDetail = data || "Request failed";
$scope.status = status;
$scope.view = './Partials/detail.html';
});
}
</script>
<div ng-controller="PageCtrl">
<input ng-model='text' />
<ul>
<li >
<span>{{text}}</span>
</li>
</ul>
</div>
Above is the skeleton of what i'm looking to do.
I realize that if I wanted to, I could call showThread() after each user action and update the data...however, because of the awy I'm looking to set up the site, It makes more sense to only change the tagid, then have everything else update immediately after, rather than picking and choosing each part of the site I want to update. i.e. there may, in addition to showThread(), be updateHeader(), changeSidebar() etc.
Thanks!
I have personally had success using a service; **Assuming that you are using 2 controllers on 1 page, I would create a service like this:
MyApp.app.service("tagDataSvc", function () {
var _tagId = {};
return {
getTagId: function () {
return _tagId;
},
setTagId: function (value) {
_tagId = value;
}
};
});
Next, inject this service into the controllers where this will be used.
In your main controller where you are controlling the TagId (PageCtrl), you would need to set the shared tagId value with a call to the service: tagDataSvc.setTagId($scope.text) You can do this explicitly, or add a $watch on $scope.text, or whatever you prefer.
Finally, in the second controller that you want to automagically update, add a $watch on this service's getTagId() function like so:
$scope.$watch(function () { return tagDataSvc.getTagId(); }, function (newValue, oldValue) {
if (newValue != null) {
$scope.tagId2 = newValue;
//reload whatever needs updating here
}
}, true);

angularjs binding/scope issue for select list?

OK switching my code to angularjs and the angular 'way', not sure what I am doing wrong.
A select list is not getting updated when the model changes unless I call $apply, and I find myself calling apply a lot.
index.html has this:
<div id='rightcol' data-ng-include="'partials/rightSidebar.html'"
data-ng-controller="rightSidebarController">
</div>
and rightSidebar.html has this:
<select id='srcList' size='10'
data-ng-model="data.source"
data-ng-click='srcOnclick()'
data-ng-options="s.title for s in data.srcList | filter:{title:data.srcFilter} | orderBy:'title'"></select>
rightSidebarController.js has this:
$scope.data = {};
$scope.data.srcList = dataProvider.getSourceList();
$scope.data.source = dataProvider.getSource();
dataProvider is a service that makes an asynchronous database call (IndexedDB) to populate srcList, which is what gets returned in dataProvider.getSource().
Is it the asynchronous database call that forces me to call $apply, or should the controller be ignorant of that?
Is there a 'better' way to do this?
Edited to add service code.
Another controller calls dataProvider.refreshSourceList:
myDB.refreshSourceList = function() {
myDB.getRecords("source", function(recs) {
myDB.srcList = recs;
$rootScope.$broadcast('SrcListRefresh');
});
};
myDB.srcList is the field being bound by $scope.data.srcList = dataProvider.getSourceList();
myDB.getRecords:
myDB.getRecords = function(storeName, callback) {
var db = myDB.db;
var recList = [];
var trans = db.transaction([storeName], 'readonly');
var store = trans.objectStore(storeName);
var cursorRequest = store.openCursor();
cursorRequest.onerror = myDB.onerror;
cursorRequest.onsuccess = function(e) {
var cursor = cursorRequest.result || e.result;
if (cursor === false || cursor === undefined) {
if (callback !== undefined) {
$rootScope.$apply(function() {
callback(recList);
});
}
} else if (cursor.value !== null) {
recList.push(cursor.value);
cursor.continue();
}
};
cursorRequest.onerror = myDB.onerror;
};
Anything you do async needs to be wrapped in $scope.$apply(). This is because angular works in a similar fashion to a game loop, however instead of constantly running, it knows to end the loop when an action is taken, and $scope.$digest() is called.
If you are using IndexedDB, I would recommend creating an angular wrapper for it, like so:
(forgive my IndexedDB code, I'm not experience with it)
angular.module('app',[])
.factory('appdb', function($rootScope){
var db = indexedDB.open('appdb', 3);
return {
get : function(table, query, callback) {
var req = db.transaction([table])
.objectStore(table)
.get(query);
req.onsuccess(function(){
$rootScope.$apply(function(){
callback(req.result);
});
});
}
};
});
This way you can be sure that any data retrieve and set on a controller scope inside of callback will have $scope.$digest() called afterward.

Resources