How to know which data has been changed in an array? - javascript

I'm trying to get which data has been changed in array. my use case is First time all data fetch from ajax and show within row and fetch new data using $http every 5 second. I need to know that if the new data is same as old one. If yes then which value has changed so I've to update that background to some color..
What I've already tried
var app = angular.module('app', []);
app.controller('listingController', function($scope, $http, $timeout){
$scope.listings;
setInterval(function(){
$http.get('_includes/ajax.php?req=get').
success(function(data, status, headers, config) {
$scope.listings = data;
console.log(data);
}).
error(function(data, status, headers, config) {
// log error
});
}, 5000);
});
app.controller('RentalDateController', function($scope, $log){
console.log($scope.listings);
$scope.$watch('listings.Third_Column', function (Third_Column, oldvalue) {
//$log.info(Third_Column, $scope.listings.First_Column);
console.log('being watched oldValue:', oldvalue, 'newValue:', Third_Column);
}, true);
});
My html is
<body ng-app="app">
<div ng-controller="listingController">
<table>
<tr>
<th>Testing</th>
<th>Pripse</th>
</tr>
<tr ng-repeat="row in listings" ng-controller="RentalDateController">
<input type="text" ng-model="row.Third_Column">
<input type="text" ng-model="row.First_Column">
<th>{{row.Third_Column}}</th>
<th>{{row.First_Column}}</th>
</tr>
</table>
</div>
</body>
I think I need to use $watch but it's not working.

You have the angular two-way data binding so it should automatically update your ng-repeat when the model changes.
I suggest the following
1) Remove RentalDate controller first.
2) Use $timeout, and on success of http use this
$scope.$apply(function(){
$scope.listing = data;
});
If that doesn't still automatically update, put the array in an object.
$scope.data = {}
$scope.data.listings = putArrayHere();
This will work because of this. Read up. :D
https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance

Try doing this:
var app = angular.module('app', []);
app.controller('listingController', function($scope, $http, $timeout){
$scope.listings;
var previousListing = [];
var newData;
setInterval(function(){
$http.get('_includes/ajax.php?req=get').
success(function(data, status, headers, config) {
$scope.listings = data;
console.log(data);
}).
error(function(data, status, headers, config) {
// log error
});
if( previousListing.length == $scope.listings.length )
{
console.log('No new data available.');
}
else
{
// length of the arrays are different, hence new data must be available
console.log('New data available!');
newData = $scope.listings.splice( 0, ($scope.listings.length - previousListing.length) ); // returns new data in the form of an array
console.log(newData);
previousListing = $scope.listings; // reset previous data variable
}
}, 5000);
});

Related

Issue in populating ajax data into table via ng-repeat

I am trying to populate a table on receiving JSON data on an Ajax get from Mongo DB.
I am able to see the received data in alert. But my table is not populated.
I am clicking the retrive button to get the data.
JS code:
$scope.retrive = function()
{
$scope.people =[];
$.ajax({
url : "https://api.mongolab.com/api/1/databases/geolocation/collections/boom?apiKey=veTqID_gkb74tG-yL4MGcS1p2RRBP1Pf",
type : "GET",
dataType: "json",
success: function(data) {
$scope.people = JSON.stringify(data);
alert($scope.people);
//alert("status = "+data.status+"descripttion"+data.description);
//console.log(data);
//document.getElementById("n1").innerHTML = data[0].name;
//alert(JSON.stringify(data));
tableCreate(data);
//alert(data[0].name);
//var json = JSON.parse(data);
//alert(json.name);
}
});
};
}]);
HTML code:
<div>
<table>
<tr>
<th>ITEM</th>
<th>DESCRIPTION</th>
<th>QUANTITY</th>
<th>LOCATION</th>
<th>CATEGORY</th>
</tr>
<tr ng-repeat="person in people">
<td>{{person.Item}}</td>
<td>{{person.Description}}</td>
<td>{{person.Quantity}}</td>
<td>{{person.Location}}</td>
<td>{{person.Category}}</td>
</tr>
</table>
</div>
Here is the Plunker Link :
http://plnkr.co/edit/OKzTApbW7ii8R0EMrOyx?p=preview
Try is like this:
Note (Just a tip ): Putting API keys within stack overflow questions is not a good idea. Keep the API key private as any body can use your key and you could blocked out from the service due to unauthorised usage.
var myApp = angular.module('myApp', []);
myApp.controller('projectController', function($scope, $http){
$scope.userDetails = [];
$scope.test = function(){
console.log("getting user projects, please wait ......");
// Simple GET request example (passing data) :
$http.get("https://api.mongolab.com/api/1/databases/geolocation/collections/boom?apiKey=YOUR-API-KEY", {
}).
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
console.log("");
$scope.userDetails = data;
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
};
});
Heres a working Plunker:
http://plnkr.co/edit/xoFuBa695E7O1g6gTcm4?p=preview
UPDATED Plunker
http://plnkr.co/edit/7E4PKbnqBDwsVptIaJ1Q?p=preview

Refresh list in ng-repeat without onclick funtion

Hello i am trying to display data from server in Angularjs App, where i got the data and use ng-repeat to display it through controller.
Here is how my controller looks like:
module.controller('FiveReasons', function($scope, $http, $rootScope, $sce) {
ons.ready(function() {
$scope.reasonsLists = {};
var reasonsListing = $http.get("http://vbought.com/design_14/index.php/design_ci/post/Clients");
reasonsListing.success(function(data, status, headers, config) {
console.log(data[0].post_title);
$scope.reasonsLists = data;
$scope.spinner = false;
});
reasonsListing.error(function(data, status, headers, config) {
alert("Can Not load the address Ajax");
});
});
});
But when the ng-repeat finish loading, the data is not displaying.
Here is how my ng-repeat is:
<ons-carousel swipeable overscrollable auto-scroll fullscreen var="carousel" name="FiveRes" class="FiveRes">
<div ng-repeat="reasonsList in reasonsLists">
<ons-carousel-item style="background: #09a4c0;" >
<div class="item-label">Number : {{reasonsList}}</div>
</ons-carousel-item>
</div>
<ons-carousel-cover></ons-carousel-cover>
</ons-carousel>
How can i now refresh the list once the data is there. Like we do "trigger("refresh")" in jquery.
After running ng-repeat, this is how i get the value but the screen is going blank.
Thank you! (In advance)
I think in this case I'd eliminate the use of ready and call your code using ng-init.
module.controller('FiveReasons', function($scope, $http) {
this.reasonsLists = {};
$scope.getReasonsLists = function() {
$scope.reasonsLists = {};
$http.get("http://vbought.com/design_14/index.php/design_ci/post/Clients")
.success(function(data, status, headers, config) {
console.log(data[0].post_title);
$scope.reasonsLists = data;
$scope.spinner = false;
})
.error(function(data, status, headers, config) {
alert("Can Not load the address Ajax");
});
};
});
then in your html on the table tag just add ng-init="getReasonsLists()"
Try this:
module.controller('FiveReasons', function($scope, $http, $rootScope, $sce) {
ons.ready(function() {
$scope.reasonsLists = {};
var reasonsListing = $http.get("http://vbought.com/design_14/index.php/design_ci/post/Clients");
reasonsListing.success(function(data, status, headers, config) {
console.log(data[0].post_title);
$scope.reasonsLists = data;
$scope.spinner = false;
});
reasonsListing.error(function(data, status, headers, config) {
alert("Can Not load the address Ajax");
});
//ADD this to notify Angular for the changes and run a digest cycle
$scope.$digest();
});
});
This is happening because the event (ons-ready) handler will not start a new $digest cycle.
To display the data without having to call $digest(), remove the ons-ready callback and execute your code directly in the controllers body. Like the example bellow:
module.controller('FiveReasons', function($scope, $http, $rootScope, $sce) {
$scope.reasonsLists = {};
var reasonsListing = $http.get("http://vbought.com/design_14/index.php/design_ci/post/Clients");
reasonsListing.success(function(data, status, headers, config) {
console.log(data[0].post_title);
$scope.reasonsLists = data;
$scope.spinner = false;
});
reasonsListing.error(function(data, status, headers, config) {
alert("Can Not load the address Ajax");
});
//No need to call $digest
});
UPDATE: Check this Codepen which is a simplified version of your code that shows only the issue. Remove $scope.$digest() from the comments to see the carousel working.
A "refresh" should not be necessary as angular uses a different approach. After certain events like "click" or the return of a $http-promise, angular goes through the binded variables and checks if they have changed - and if so - changes the DOM.
In your case I think the promise is returning before you add the success-callback. Try chaining it like:
$http.get("http://vbought.com/design_14/index.php/design_ci/post/Clients").success(function(data, status, headers, config) {
console.log(data[0].post_title);
$scope.reasonsLists = data;
$scope.spinner = false;
}).error(function(data, status, headers, config) {
alert("Can Not load the address Ajax");
});
In other cases you can use $scope.$apply() but I think this should tell you, that you can't nest $digests as there should be one going on after a $http-request.

How to add eventlisteners after simple get request json in angularjs?

Ok so I am experimenting with Angular but I have run into a problem and maybe it is because I haven't adopted the Angular way of thinking yet, but this is basically what I ran into.
I get some data with a JSON request and show this data in a list using ng-repeat. So far so good. No errors in the console, but it does not attach the eventlistener to the ng-repeat elements. The code is fine, because with non ng-repeat elements it works like a charm. Someone else ran into this problem and how did you solve it? Thanks in advance.
<div ng-controller="basictrl">
<h1>Lijst van producten</h1>
<ul ng-repeat="item in producten">
<li>{{item.naam}}</li>
<li>{{item.prijs}}</li>
</ul>
</div>
JS
angular.module("app", ['ngRoute'])
.controller("basictrl", function ($scope, $http, producteffecten) {
$scope.producten = null;
$http({
method: 'GET',
url: 'producten.json'
}).
success(function (data, status, headers, config) {
$scope.producten = data;
$scope.showdescription = producteffecten.showdescription;
}).error(function (data, status, headers, config) {});
})
.factory('producteffecten', function() {
var effecten = {};
effecten.showdescription = $('ul').hover(function (){
$(this).append("<p>Test</p>");
});
return effecten;
})
The simple answer is: you can use $('ul').on("hover",function(){}). But this is not the angular way of thinking. The first improvement you could make is this:
add ng-mouseover="muisOverEffectje()" to the ul in the html
add $scope.muisOverEffectje=function(){ your event code} to the angular page
The next step to avoid adding the code with jquery to make it even more angular could be something like this:
add a parameter which gives the selected item to your event : muisOverEffectje(item)
add ng-show="showDescription" to the the ul
put show-description to true in the event handler
The last step could be: Make a directive for you . Like a product component for example.
Setting a timeout works, but it is hacky I guess. I will try to rewrite in a more angular way.
.factory('producteffecten', function() {
var effecten = {};
//SETTING TIMEOUT WORKS SOMEHOW
effecten.showdescription = setTimeout(function() {
$('ul').hover(function (){
$(this).append("<p>Test</p>");
});
}, 10);
return effecten;
})
You could also write an directive. Which is the nicest way in angular to do this kind of stuff:
Html:
<div ng-controller="basictrl">
<h1>Lijst van producten</h1>
<ul ng-repeat="item in producten" hover-text="item.effect">
<li>{{item.naam}}</li>
<li>{{item.prijs}}</li>
</ul>
</div>
js:
.controller("basictrl", function ($scope, $http, producteffecten) {
$scope.producten = null;
$http({
method: 'GET',
url: 'producten.json'
}).
success(function (data, status, headers, config) {
$scope.producten = data;
$scope.showdescription = producteffecten.showdescription;
}).error(function (data, status, headers, config) {});
})
.directive("hoverText",function(){
return {link:function(scope,elem,attr){
var insertElem=$("<div class='hovertext'>"+scope.hoverText+"</div>")
elem .mouseenter(function() {
insertElem.appendTo(elem);
})
.mouseleave(function() {
insertElem.remove();
});
},
scope:{"hoverText":"="}
};
});

AngularJS: display a select box from JSON data retrieved by http GET (from REST service)

I have a REST service that I made which returns a json string which is simply a set of strings (I used Gson to generate this string (Gson.toJson(mySetOfStrings))
So I have added to my index.html:
<div ng-controller="ListOptionsCtrl">
<form novalidate>
<button ng-click="refreshList()">refresh</button>
<select name="option" ng-model="form.option" ng-options="o.n for o in optionsList></select>
</form>
</div>
and in my script:
var ListOptionsCtrl = function ListOptionsCtrl($scope, $http) {
$scope.refreshList = function() {
$http({
method: 'GET'
url: '*someurl*'
}).
success(function(data) {
$scope.optionsList = angular.fromJson(data);
});
};
}
Unfortunately all this produces in my select box is an empty list. When I see what the response to the GET request is it returns a json string with content in it so I do not see why nothing is being added to this element. What am I doing wrong here? thanks
It is because Angular does not know about your changes yet. Because Angular allow any value to be used as a binding target. Then at the end of any JavaScript code turn, check to see if the value has changed.
You need to use $apply
var ListOptionsCtrl = function ListOptionsCtrl($scope, $http) {
$scope.refreshList = function() {
$http({
method: 'GET'
url: '*someurl*'
}).
success(function(data) {
$scope.$apply(function () {
$scope.optionsList = angular.fromJson(data);
});
});
};
}
Try this.
More about how it works and why it is needed at Jim Hoskins's post
You should check for $digest error by doing if(!$scope.$$phase) { ... } before doing $apply.
success(function(data) {
if(!$scope.$$phase) {
$scope.$apply(function () {
$scope.optionsList = angular.fromJson(data);
});
}
});

AngularJS: Async $http.jsonp call from a service

I am trying to write a simple app that does the following:
1. User inputs 2 parameters & clicks a button
2. Angular calls an external JAVA Servlet that returns JSON
3. App outputs the json string to the screen
I have a problem however, as when i click the button nothing happens. I believe (due to testing) that the reason this happens is that since the call is async, the variable that is returned is null.
Pertinent code:
controllers.js
function myAppController($scope,kdbService) {
$scope.buttonClick = function(){
var dat = kdbService.get($scope.tName,$scope.nRows);
$scope.data = dat;
}
}
services.js
angular.module('myApp.services', []).factory('kdbService',function ($rootScope,$http){
var server="http://localhost:8080/KdbRouterServlet";
return {
get: function(tname,n){
var dat;
$http.jsonp(server+"?query=krisFunc[`"+tname+";"+n+"]&callback=JSON_CALLBACK").
success(function(data, status, headers, config) {
console.log("1");
console.log(data);
dat=data;
}).
error(function(data, status, headers, config) {
alert("ERROR: Could not get data.");
});
console.log("2");
console.log(dat);
return dat;
}
}
});
index.html
<!-- Boilerplate-->
<h1>Table Viewer</h1>
<div class="menu" >
<form>
<label for="tName">Table Name</label>
<input id="tName" ng-model="tName"><br>
<label for="nRows">Row Limit</label>
<input id="nRows" ng-model="nRows"><br>
<input type="submit" value="Submit" ng-click="buttonClick()">
</form>
</div>
{{data}}
<!-- Boilerplate-->
When i execute the code and push the button, nothing happens. However, if i look in my log, i see this:
2
undefined
1
Object {x: Array[2], x1: Array[2]}
Clearly, what is happening is that the success function returns after the get function has returned. Therefore the object put into $scope.data is undefined, but the object returned from the jsonp call is left behind.
Is there a correct way to be doing this? Most of the tutorials I see assign the data to the $scope variable inside the success function, thereby skipping this problem. I want my service to be detached if possible.
Any help would be appreciated.
i would do something like that :
controller
function myAppController($scope,kdbService) {
$scope.kdbService = kdbService;
$scope.buttonClick = function(){
$scope.kdbService.get($scope.tName,$scope.nRows);
}
}
service
angular.module('myApp.services', []).factory('kdbService',function ($rootScope,$http){
var server="http://localhost:8080/KdbRouterServlet";
return {
data:{},
get: function(tname,n){
var self = this;
$http.jsonp(server+"?
query=krisFunc[`"+tname+";"+n+"]&callback=JSON_CALLBACK").
success(function(data, status, headers, config) {
console.log("1");
console.log(data);
self.data = data;
}).
error(function(data, status, headers, config) {
alert("ERROR: Could not get data.");
});
}
}
});
html
{{kdbService.data}}
OR
use continuation in the get method :
controller
function myAppController($scope,kdbService) {
$scope.buttonClick = function(){
kdbService.get($scope.tName,$scope.nRows,function success(data){
$scope.data = data;
});
}
}
service
get: function(tname,n,successCallback){
$http.jsonp(server+"?query=krisFunc[`"+tname+";"+n+"]&callback=JSON_CALLBACK").
success(function(data, status, headers, config) {
successCallback(data,status,headers,config);
}).
error(function(data, status, headers, config) {
alert("ERROR: Could not get data.");
});
}
OR use the $resource service
http://docs.angularjs.org/api/ngResource.$resource ( you'll need the angular-resource module
code not tested.
I want my service to be detached if possible.
then put the "data object" in a "data service" calling a "data provider service". You'll have to call the "data provider service" somewhere anyway. There is no skipping this problem in my opinion, since that's how javascript work.
also use angular.controller("name",["$scope,"service",function($s,s){}]);
so you will not need to care how parameters are called , as long as they are defined and injected properly.

Categories