I have such json representation of a post by its id:
http://127.0.0.1:8000/update/1?format=json
{"title": "about me", "content": "I like program", "created": "2014-11-29T18:07:18.173Z", "rating": 1, "id": 1}
I try to update rating by button click:
<button ng-click="click(post.id)">Click me</button>
I have such javascript code:
<script>
var demoApp = angular.module('demoApp',['ngResource']);
demoApp.controller( 'AllPosts', function ($scope, $http)
{
$http.get('/blogpost/?format=json').success(function(data,status,headers,config)
{
$scope.posts = data.results;
$scope.predicate = '-title';
$scope.click = function(post_id, $resource){
var Post = $resource('/update/:PostId ',{PostId:post_id,format:'json'} );
post = Post.get({PostId:post_id}, function() {
post.rating = post.rating+ 1 ;
post.$save();
});
};
}).error(function(data,status,headers,config)
{} )
;})
</script>
Peharps i have mistake because in json i have a single object. But i dont really know
Besides i have such view to have a json by certain post by its id:
class UpdateModel(generics.RetrieveUpdateDestroyAPIView):
lookup_field = 'id'
queryset = BlogPost.objects.all()
serializer_class = BlogPostSerializer
permission_classes = (AllowAny,)
A quick tidy up of your script tag shows that you are only defining the function click if the http call was successful.
I would suggest moving the definition of the click method outside of the success callback.
You may also be running into a race condition that the click function has not been defined before clicking the actual button. Regardless you will want to move that function definition to where the controller is actually created.
Suggested edits (moved click definition outside of http call response):
var demoApp = angular.module('demoApp', ['ngResource']);
demoApp.controller('AllPosts', function($scope, $http, $resource) {
$scope.click = function(post_id) {
var Post = $resource('/update/:PostId ', {
PostId: post_id,
salutation: 'json'
});
post = Post.get({
PostId: post_id
}, function() {
post.rating = post.rating + 1;
post.$save();
});
};
$http.get('/blogpost/?format=json').success(function(data, status, headers, config) {
$scope.posts = data.results;
$scope.predicate = '-title';
}).error(function(data, status, headers, config) {});
})
Updates:
Injected $resource into the controller
Removed $resource from click function params
Related
I have two controllers with same data depending upon language selection controller will load.When an item is clicked on the list item is loading but the problem is when other items are clicked angular ready function is not working and am seeing previously loaded item only
.controller('EnCtrl', function($scope,sharedCartService) {
var cart = sharedCartService.cart;
$scope.menu_items=[
{"p_id":"1",
"p_name":"coffe ",
"p_image_id":"coffe",
"p_price":"50"
},
{"p_id":"2",
"p_name":"Tea",
"p_image_id":"Tea",
"p_price":"50"
},
{"p_id":"3",
"p_name":"Masala",
"p_image_id":"Masala",
"p_price":"50"
}];
$scope.showProductInfo=function (id,img,name,price) {
sessionStorage.setItem('product_info_id', id);
sessionStorage.setItem('product_info_img', img);
sessionStorage.setItem('product_info_name', name);
sessionStorage.setItem('product_info_price', price);
window.location.href = "#";
};
$scope.addToCart=function(id,image,name,price){
cart.add(id,image,name,price,1);
};
})
Kctrl
.controller('kCtrl', function($scope,sharedCartService) {
var cart = sharedCartService.cart;
$scope.menu_items=[
{ "p_id": "1",
"p_name": "ಕಾಫಿ",
"p_image_id": "coffe",
"p_price": "50"
},
{ "p_id": "2",
"p_name": "ಚಹಾ",
"p_image_id": "Tea",
"p_price": "50"
},
{ "p_id": "3",
"p_name": "ಮಸಾಲಾ",
"p_image_id": "Masala",
"p_price": "50"
}];
$scope.showProductInfo=function (id,img,name,price) {
sessionStorage.setItem('product_info_id', id);
sessionStorage.setItem('product_info_img', img);
sessionStorage.setItem('product_info_name', name);
sessionStorage.setItem('product_info_price', price);
window.location.href = "#";
};
$scope.addToCart=function(id,image,name,price){
cart.add(id,image,name,price,1);
};
})
Product Controller
.controller('productCtrl', function($scope) {
//onload event
angular.element(document).ready(function () {
$scope.id= sessionStorage.getItem('product_info_id');
$scope.img= "img/"+ sessionStorage.getItem('product_info_img')+".jpg";
$scope.name= sessionStorage.getItem('product_info_name');
$scope.price= sessionStorage.getItem('product_info_price');
});
En.html
<ion-list ng-repeat="item in menu_items" >
<h2 ng-click="showProductInfo(item.p_id,item.p_image_id,item.p_name,item.p_price)" > {{item.p_name}} </h2>
<p ng-click="showProductInfo(item.p_id,item.p_image_id,item.p_name,item.p_price)">{{item.p_price}}</p>
</ion-list>
Productpage.html
<div>
<p> {{name}}</p>
<p>{{price}}</p>
</div>
Updated after comments.When an item is clicked dataupdate message is displayed.Item information is not getting
.
controller('EnCtrl', function($scope,sharedCartService,$rootScope) {
var cart = sharedCartService.cart;
$scope.menu_items=[
{"p_id":"1",
"p_name":"coffe ",
"p_image_id":"coffe",
"p_price":"50"
},
{"p_id":"2",
"p_name":"Tea",
"p_image_id":"Tea",
"p_price":"50"
},
{"p_id":"3",
"p_name":"Masala",
"p_image_id":"Masala",
"p_price":"50"
}];
$scope.showProductInfo=function (id,img,name,price) {
$rootScope.$broadcast('dataUpdate', {id: id,img: img,name: name,price: price})
window.location.href = "#";
};
$scope.addToCart=function(id,image,name,price){
cart.add(id,image,name,price,1);
};
})
Product Controller
.controller('productCtrl', function($scope,$rootScope) {
$rootScope.$on('dataUpdate', function(data) {
$scope.id = data.id;
$scope.img = data.img;
$scope.name = data.name;
$scope.price=data.price;
})
})
Plunker demo
https://plnkr.co/edit/zhvBzOzDtgOiTEGjBqAp?p=preview
#user3698911, in addition to #Bartek Fryzowicz's answer,
You may also want to look at:
angular.element
Note from angular:
(deprecated, use angular.element(callback) instead of
angular.element(document).ready(callback))
Actually .ready method is not Angular function but jqLite method (or jQuery method if you included it on your page; by default angular uses jqLite but if you include jQuery it will be used instead). angular.element(document) returns an element wrapped in jqLite object and ready is method of this object. Back to your main problem: 'ready' method callback is called only once when DOM is fully loaded, it's not called again until next page reload. Please check docs of ready method
You can broadcast an event with your data on $rootScope in click handler and then access this data in another controller in the event listener.
So in you click handler do this:
$rootScope.$broadcast('dataUpdate', {id: id, name: name, img: img, price: price})
And in product controller add this (use event data to updated controller $scope):
$rootScope.$on('dataUpdate', function(data) {
$scope.id = data.id;
$scope.img = data.img;
$scope.name = data.name;
...
});
Update after comments questions
You have to inject $rootScope into each controller in which you want to use it:
.controller('EnCtrl', function($scope,sharedCartService, $rootScope) {
...
.controller('productCtrl', function($scope, $rootScope) {
Answer update
I've noticed that you redirect in your click handler. So please try just removing ready handler so that your controller reads localStorage every time it's initialised:
.controller('productCtrl', function($scope) {
$scope.id= sessionStorage.getItem('product_info_id');
$scope.img= "img/"+ sessionStorage.getItem('product_info_img')+".jpg";
$scope.name= sessionStorage.getItem('product_info_name');
$scope.price= sessionStorage.getItem('product_info_price');
}
I am making my first project using Angularjs 1.4.3.
In my controller I am making a http request, in the success method of this http request I am updating a scope variable. In http call I am getting the latest values but in the view side its not updating the values.
Plunker Link (#rupesh_padhye thanks). (Since it is calling the servlet action, so no data will be shown in Plunker)
app.controller('measuresCtrl', ['$scope', '$modal', '$http', function($scope, $modal, $http) {
$scope.groups = []
$scope.loadAllMeasure = function() {
$http.get("fetchAllMeasure")
.success(function(data) {
console.log("Before insert");
console.log($scope.groups);
$scope.groups = data.measures;
console.log("After insert");
console.log($scope.groups);
})
.error(function() {
});
};
$scope.loadAllMeasure();
$scope.submit = function (form) {
$http({
method: 'POST',
url: 'saveMeasure',
data: {
id: form.id,
name: form.name,
description: form.description
},
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function(data, status, headers, config) {
$scope.loadAllMeasure();
}).error(function(data, status, headers, config) {
});
}
})
And whenever I am performing any CRUD operation on measures I am calling a method $scope.loadAllMeasure();. But its not updating the values in the view (jsp) page.
I have tried $scope.$apply method but I am getting Error: $digest already in progress.
When I printed the value for $scope.groups using console.log inside success method, then its showing the latest values.
In my view (jsp) page I am just using ng-repeat function to show all the records in table format.
Code for my view page (minimal code) -
<div ng-repeat="group in groups | orderBy:'name'">
<div>
<input type="checkbox" id="checkbox-{{group.id}}" class="ui-checkbox" /><label for="checkbox-{{group.id}}">{{group.name}}</label>
</div>
<div>{{ group.description}}</div>
<div>
<div class="fa fa-pencil button" data="{{group.id}}" id="{{::elementId}}" ng-click="showEditForm(group.id, $event)"></div>
<div class="fa fa-trash button" data="{{group.id}}" ng-click="deleteGroup(group.id)"></div>
<div class="fa fa-clone button" data="{{group.id}}" id="{{::elementId}}" ng-click="showCloneForm(group.id, $event)"></div>
</div>
</div>
Values in console.log are
Before insert
Object { id=1, description="Measure Description1", name="Demo"}]
And
After Insert
[Object { id=1, description="Measure Description1", name="Demo"}, Object { id=2, description="Description2", name="Demo2"}]
How to update scope variable value in view after http call?
After assigning the new data to a $scope variable call:
$scope.$digest();
This will update the current scopes values
reference here: https://docs.angularjs.org/api/ng/type/$rootScope.Scope
I cant see anything wrong with your example code.
I have created a JSFiddle to try and help you.
The server call has been replaced by a setTimeout function that returns a promise.
Please see JSFiddle https://jsfiddle.net/sjwkbzxa/
Please see example below:
<div data-ng-controller="TestController as vm">
<button data-ng-click="loadAllMeasure()">Load List from Server</button>
<ul>
<li data-ng-repeat="group in groups | orderBy:'name'">
<span>{{group.description}}</span>
</li>
</ul>
</div>
The javascript:
angular.module('application',[]).controller("TestController", ['$scope', '$q', function($scope, $q){
$scope.groups = [{ id:1, description:"Initial List", name:"Demo"}];
$scope.loadAllMeasure = function(){
loadData().then(function(data){
$scope.groups = data;
});
};
function loadData(){
var deferred = $q.defer();
setTimeout(function(){
var data = [{ id:1, description:"Measure Description1", name:"Demo"}, { id:2, description:"Description2", name:"Demo2"}];
deferred.resolve(data);
}, 3000);
return deferred.promise;
}
}]);
Maybe you are missing something on your side that we cant see?
I'm a little late to answer this, but here are my 2 cents:
A simple assignment of the server data (response.data) to a $scope object didnt seem to work for me
$scope.something = response.data //didn't work
So, I returned a promise object from the service into the controller and then use
angular.copy(response.data,$scope.something)
to copy the values returned from the server. You could also pass the $scope.something to the service as a parameter to the function and have angular.copy in the service function as well, but i don't know if it's a good practise to do that.
$scope.loadAllMeasure = function() {
CalltoServer();
};
CalltoServer = function() {
return $http.get("fetchAllMeasure")
.success(function(data) {
$scope.groups = data.measures;
})
.error(function() {
});
}
try this , the success will be after 2 or 3 seconds so i guess inside the event it takes rist to bind
Hey I also faced the same issue and if anyone is still looking, it is caused by change in the $scope variable inside the $http. I think a new $scope is being created inside the success function(some prototypical inheritance stuff).
So make a copy of the variable $scope, something like
var s = $scope;
and then change
s.groups = someData;
Your code:
app.controller('measuresCtrl', ['$scope', '$modal', '$http', function($scope, $modal, $http) {
var s = $scope;
$scope.groups = []
$scope.loadAllMeasure = function() {
$http.get("fetchAllMeasure")
.success(function(data) {
console.log("Before insert");
console.log($scope.groups);
s.groups = data.measures;
console.log("After insert");
console.log($scope.groups);
})
.error(function() {
});
};
$scope.loadAllMeasure();
$scope.submit = function (form) {
$http({
method: 'POST',
url: 'saveMeasure',
data: {
id: form.id,
name: form.name,
description: form.description
},
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function(data, status, headers, config) {
$scope.loadAllMeasure();
}).error(function(data, status, headers, config) {
});
}
})
I have a custom directive for soundcloud that requires the soundcloud url. The soundcloud url is fetched from the database through the $http service, however, the div for the soundcloud custom directive is loaded and requires the value of the soundcloud url before it is even defined.
The Plangular Directive Code I got is here:
https://github.com/jxnblk/plangular/blob/master/src/plangular.js *I did not develop this
This is my HTML code:
<div plangular="{{soundcloud}}">
<button ng-click="playPause()">Play/Pause</button>
<progress ng-value="currentTime / duration || 0">
{{ currentTime / duration || 0 }}
</progress>
</div>
And this is the Angular Code:
displaySong.controller('song', ['$scope', '$http', 'fetchSong', function($scope, $http, fetchSong) {
$scope.songID
$scope.songName;
//Controller properties
$scope.songPromise; //The song promise for fetching
$scope.init = function(songID, userID) {
$scope.songID = songID;
$scope.userID = userID;
$scope.songPromise = $http({
method: "post",
url: fetchSong,
data: {
song_id: $scope.songID
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(function(successResponse) {
console.log('Successfully fetched song');
console.log(successResponse);
var song = successResponse.data;
$scope.songID = song.song_id;
$scope.songName = song.song_name;
$scope.songType = song.song_type;
$scope.songEmbed = song.song_embed;
$scope.soundcloud = song.song_embed;
}, function(errorResponse) {
console.log('Error fetching');
$scope.songID = null;
});
};
}]);
I know it's a problem with the asynchronous nature because when I add this line in the beginning of my song controller:
$scope.soundcloud = "https://soundcloud.com/jshigley/shine";
It works perfectly fine. I've also noticed that when I spam the play/pause button that DOES come up from the directive, I get multiple console errors of "HTTP 404 Not Found", which leads me to believe it's trying to find a track of undefined url
Since it's a div directive and not a function call I can't use promises such as chaining a then to my $scope.songPromise. I've thought of putting it into a controller and having the controller do something like $timeout for 5 seconds, but I don't think this delays the execution of the DOM.
The soundcloud URL DOES end up getting loaded, but it remains undefined in the eyes of the plangular directive (I've actually encountered lots of these problems with bad timing of loading scope and directives). Any Angular Wizards willing to teach me how to tame the asynchronous nature of AngularJS?
You can use $watch in the custom directive to watch when url attributes is changed.
In
link: function(scope, el, attr) {
change from
if (src) {
resolve({ url: src, client_id: client_id }, function(err, res) {
if (err) { console.error(err); }
scope.$apply(function() {
scope.track = createSrc(res);
if (Array.isArray(res)) {
scope.tracks = res.map(function(track) {
return createSrc(track);
});
} else if (res.tracks) {
scope.playlist = res;
scope.tracks = res.tracks.map(function(track) {
return createSrc(track);
});
}
});
});
}
to
scope.$watch('attr.plangular', function(newVal) {
resolve({ url: attr.plangular, client_id: client_id }, function(err, res) {
if (err) { console.error(err); }
scope.$apply(function() {
scope.track = createSrc(res);
if (Array.isArray(res)) {
scope.tracks = res.map(function(track) {
return createSrc(track);
});
} else if (res.tracks) {
scope.playlist = res;
scope.tracks = res.tracks.map(function(track) {
return createSrc(track);
});
}
});
});
}, true);
If you dont want to change the directive then you might want to use ng-if to load that plangular div only when you get the url.
<div plangular="{{soundcloud}}" ng-if="haveurl">
and in the angular code :
}).then(function(successResponse) {
console.log('Successfully fetched song');
console.log(successResponse);
$scope.haveurl = true;
Try using ng-show like this to only show the div once your $http request has been completed.
<div ng-show="httpRequestComplete" plangular="{{soundcloud}}">
<button ng-click="playPause()">Play/Pause</button>
<progress ng-value="currentTime / duration || 0">
{{ currentTime / duration || 0 }}
</progress>
</div>
displaySong.controller('song', ['$scope', '$q', '$http', 'fetchSong', function($scope, $http, fetchSong) {
/* add $q promise library */
$scope.songID
$scope.songName;
var httpRequest = function() {
var deferred = $q.defer();
$http({
method: "post",
url: fetchSong,
data: {
song_id: $scope.songID
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).success(function(successResponse) {
deferred.resolve({response: successResponse});
console.log('Successfully fetched song', successResponse);
var song = successResponse.data;
$scope.songID = song.song_id;
$scope.songName = song.song_name;
$scope.songType = song.song_type;
$scope.songEmbed = song.song_embed;
$scope.soundcloud = song.song_embed;
}).error(function(error) {
console.log(error);
});
return deferred.promise;
};
httpRequest().then(function(response) {
$scope.httpRequestComplete = true;
console.log('div will show');
};
}]);
I would do something like this that delays the showing of the div until httpRequestComplete = true, or until your promise ($q) is fulfilled. This will make sure that your div isn't loaded until you have the information available.
i am using the below format to get a JSON object from my localhost. The JSON is pretty complicated and lengthy so , using jquery to populate the HTML is getting complicated.
function processmsg(msg) {
var jobj = JSON.parse(msg);
if (typeof jobj === 'object')
{
// Parse the JSON
}
document.getElementById("messages").innerHTML = globalTag;
}
}
function waitForMsg() {
$.ajax({
type: "GET",
url: "1.json",
cache: false,
timeout: 50000,
success: function (data) {
processmsg(data);
if (!data) {
setTimeout(
waitForMsg,
1000
);
};
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
setTimeout(waitForMsg, 15000);
processmsg("error");
}
});
};
$(document).ready(function () {
waitForMsg();
processmsg("loading");
});
I would like to use the format like {{jobj.entries}}. something like this. This can be done on angularJS. can you guys please suggest me how to do the same in angular ?
i want to query the JSON every 1 min and when the data is found i want to cancel the interval. I dono how to do it in angularjs.
==================update================
i got below code snippet. It is working fine, But how do i stop the url query once the json object is obtained..
var app = angular.module('urlanalyzer', []);
app.controller('jsonController', function($scope, $http) {
$scope.getData = function(){
var url = "{% static "" %}tmp/{{url_hash}}/{{url_json}}";
$http.get(url)
.success(function(data, status, headers, config) {
console.log(data);
});
};
if (!$scope.data){
setInterval($scope.getData, 2000);
}
The issue here is the json object will be available after 3 sec only.
var app = angular.module('urlanalyzer', []);
app.controller('jsonController', ['$scope','$http','$timeout',function($scope, $http, $timeout) {
$scope.getData = function(){
var url = "{% static "" %}tmp/{{url_hash}}/{{url_json}}";
$http.get(url)
.success(function(data, status, headers, config) {
if(!data)
$timeout(function(){
$scope.getData()
}, 2000)
else{
$scope.myData = data.data? data.data:data;
$scope.showError = false;
}
})
.error(function(msg) {
$timeout(function(){
$scope.getData()
}, 2000)
$scope.processMessage(msg)
});
};
$scope.processMessage = function(msg){
if(angular.isString(msg))
$scope.errorMessage = msg;
else if(angular.isObject(msg)){
$scope.errorMessage = msg.message // the property you want;
}
$scope.showError = true;
}
$scope.getData();
}])
HTML:
<div ng-controller="jsonController">
<div ng-show="showError">
{{errorMessage}}
</div>
<div id="myDatacontainer">
//you can bind any propery of your data by using angular direvtives
//look at ng-bing, ng-if etc. directives
{{myData.name}} ...
</div>
</div>
Hope it help.
Consider you have following JSON data stored in a scope variable named data:
$scope.data = {
"array": [
1,
2,
3
],
"boolean": true,
"null": null,
"number": 123,
"object": {
"a": "b",
"c": "d",
"e": "f"
},
"string": "Hello World"
}
Then you write your HTML in the following way like:
<div>
Boolean: {{data.boolean}}
</div>
<div>
Number: {{data.number * 2}}
</div>
<div>
Array:
<p ng-repeat="(key, value) in data.object"> {{key}} : {{value}}</p>
</div>
Another way to bind <div ng-bind="data.string"></div>
Here you can stop your call. You can use enhanced angular service $interval for this:
$scope.getData = function(){
var url = "{% static "" %}tmp/{{url_hash}}/{{url_json}}";
$http.get(url)
.success(function(data, status, headers, config) {
console.log(data);
$interval.cancel($scope.intervalObject); // cancel the interval when data is loaded
});
};
if (!$scope.data){
$scope.intervalObject = $interval($scope.getData, 2000);
}
if (!$scope.data){
setInterval($scope.getData, 2000);
}
since $scope.data is not set it'll continue calling the request(since you are not setting $scope.data anywhere).
Edit: Also, use angularjs $interval since it's the angular way of using setInterval and it keeps track of the $digest cycle
I am trying to return an object, taht I populate in a forEach loop, with angulars $scope from a controller, but when I try to loop it out with ng-repeat I get no result.
When i console.log the object I get the expected result
But when I try to return it with $scope and show it with ng-repeat I get no results what so ever.
Here is my controller
myAppControllers.controller('musicCtrl', ['$scope', '$http', function($scope, $http) {
var i = 0,
playlists = {};
// Get the playlists from soundcloud
$http({ method: 'GET', url: 'http://api.soundcloud.com/users/gimle-sound-tjek/playlists.json?client_id=c2dfe07de1d18d689516884ce22b7aae' }).
success(function(data) {
data.forEach(function() {
// Populate the object
playlists[i] = {
"title" : data[i].title,
"permalink": data[i].permalink,
"genre": data[i].genre
}
i++;
});
console.log(playlists);
$scope.playlists;
}).
error(function() {
$scope.playlists = '';
});
}]);
My ng-repeat looks like this
<div ng-repeat="playlist in playlists">
<h3>{{ playlist.title }}</h3>
...
I am expecting that is has something to do with the way I send the object back with $scope.playlists?
First of all maybe use push instead this i++ fun.
You push those playlist entries into the playlist variable outside the scope.
myAppControllers.controller('musicCtrl', ['$scope', '$http', function($scope, $http) {
$scope.playlists= [];
// Get the playlists from soundcloud
$http({ method: 'GET', url: 'http://api.soundcloud.com/users/gimle-sound-tjek/playlists.json?client_id=c2dfe07de1d18d689516884ce22b7aae' }).
success(function(data) {
data.forEach(function(entry) {
// Populate the object
$scope.playlists.push({
"title" : entry.title,
"permalink": entry.permalink,
"genre": entry.genre
});
//OR: $scope.playlists.push(entry);
});
}).
error(function() {
$scope.playlists = '';
});
}]);
What if you try $scope.playlists = [] instead of var playlist = {}