AngularJS - View not updating with new array - angularjs

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.

Related

How could I show the loading popop before the fetching data and rendering task are done

I have a page which will call search_hotels method.
It should wait about 2 seconds for the Server returns the JSON.
And the size of the returned JSON contains 2 thounds items.
It also needs 2~3 seconds to process and render all items with ng-repeat.
What the better practice to show the loading window for telling people to wait?
function search_hotels(q_param) {
roomSkuService.search(q_param).$promise.then(function(resp) {
_.each(resp, function(item) {
var region = item.hotel.region;
if ($scope.region.list.indexOf(region) < 0) {
$scope.region.list.push(region)
}
});
$scope.hotels = _.groupBy(resp, function(row) {
return row.hotel_id;
});
});
}
I would recommend u use $timeout to hide the loading window after the rendering finishes.
function search_hotels(q_param) {
//show the loading window
roomSkuService.search(q_param).$promise.then(function(resp) {
_.each(resp, function(item) {
var region = item.hotel.region;
if ($scope.region.list.indexOf(region) < 0) {
$scope.region.list.push(region)
}
});
$scope.hotels = _.groupBy(resp, function(row) {
return row.hotel_id;
});
//execute after rendering
$timeout(function(){
//hide loading window
},0);
});
}

View not updating - angular, firebase

This function fires once at page load, but then never again. I've tried $watch, $apply, and firebase's ref.on('value', ... but no dice. The model changes for the value of scope.job.getApplicants(), but scope.applicants_ is not refreshing when this happens.
function go() {
var p = [];
// scope.job.getApplicants() returns a $firebaseArray of user IDs
scope.job.getApplicants().$loaded().then(function(list) {
list.forEach(function(app) {
// User_(app.$id) returns a $firebaseObject
var user = User_(app.$id);
p.push(user);
})
});
return p;
}
scope.applicants_ = go();
This is how I resolved the problem:
ref.on('value', function(apps) {
var applicantIDs = Object.keys(apps.val());
scope.applicants_ = applicantIDs.map(function(app) {
return User_(app);
});
});

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();

How can I get changed filter text for each column in Angular ui grid?

I m using new angular uigrid. But I think documentation is really poor for searching. I did not find necessary infos for filtering. I will use server side filtering . SO I have to get changed filter text for each column. Please help me?
I tried this code. But probably it was for ng grid(old grid)
$scope.$watch('completedgridOptions.filterOptions.filterText', function (newVal, oldVal) {
if (newVal !== oldVal) {
console.log("Filter");
}
}, true);
if you want to check what is what:
$scope.gridApi.core.on.filterChanged($scope, function () {
var grid = this.grid;
$.each(grid.columns, function (index, column) {
switch (column.field) {
case 'externalIdentifier':
$scope.identifier = column.filters[0].term;
break;
case 'name':
$scope.name = column.filters[0].term;
break;
case 'status':
$scope.status = column.filters[0].term;
break;
....
....
....
}
});
//you have to move it by hand, if you are on the third page and filter, it will stay on the third page, even though you will not have any data there
grid.options.paginationCurrentPage = 1;
//use the timeout so that you don't get a db call at every key pressed
if (angular.isDefined($scope.filterTimeout)) {
$timeout.cancel($scope.filterTimeout);
}
$scope.filterTimeout = $timeout(function () {
getPage(); //this will call your data from the db
}, 500);
});
var getPage = function () {
itemsPerPage = paginationOptions.pageSize;
offset = (paginationOptions.pageNumber -1) * paginationOptions.pageSize;
getDataByFilter($scope.name, $scope.identifier, $scope.status, offset, itemsPerPage)
}
I am new using angular as well but try this:
$scope.gridApi.core.on.filterChanged($scope, function () {
var grid = this.grid;
for (var i = 0; i < objGrid.columns.length; i++) {
term = objGrid.columns[i].filter.term;
field = objGrid.columns[i].field;
console.log('Field: ' + field + '\nSearch Term: ' + term);
}
});
$scope.gridOptions.data = $scope.data;//initialiazing grid with data
$scope.gridApi.core.on.filterChanged($scope, function () {
var grid = this.grid;
//do your stuff here
});
Basically I was able to use the filterchanged feature on grid only after the grid gets initialized with data.
So put the snippet as suggested in the thread only after initializing grid with data.
I have used $timeout as below for my convinience.
$timeout(function () {
$scope.getData();//get your data from ajax call or from where ever your data is
$scope.assignDatatoGrid();//assign the data to grid or initialize the grid with data
$scope.$apply();
//this feature is available only after the grid gets populated with data
$scope.gridApi.core.on.filterChanged( $scope, function() {
var grid = this.grid;
});
}, 2000);
It worked for me
Thank you

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