I started playing with Angular.js recently, and got a demo project working pretty well. However, when I attempted to load the data from a backend web service versus just a hard coded array I started getting hung up. Specifically the page doesnt seem to properly data bind after i set the $scope using $.getJSON().done(...). Instead of just assigning a value to $scope after .getJSON is done, should I be doing it somewhere else/differently? I searched high and low and really couldnt find any good examples of angular thats pulling intial data from a backend.
Thanks in advance for any help with this!
Since you are trying to update the $scope outside of Angular you will have to make your model changes using the $apply method on the scope.
Maybe something like:
$.getJSON('ajax/test.json', function(data) {
$scope.$apply(function(){
$scope.modelData = data;
});
});
The preferred way to access a backend with AngularJS would be to use the $http or $resource service in place of jQuery. You won't have to use $scope.$apply you can just update your $scope.modelData directly.
This post has a good fiddle of updating a model outside of Angular code.
or instead of wrapping with apply, just call it at the end of the callback function like
$.getJSON('ajax/test.json', function(data) {
$scope.data = data;
$scope.$apply();
});
Related
As my app initializes, the call to the api happens:
.run(function($ionicPlatform, $http, $localstorage, $model) {
$http.get($model.apiurl).success(function(data) {
$localstorage.setObject('data', data);
// reload template here!
});
})
When the api call has succeeded and the localstorage object is set, I want to reload my template (tab-categories.html) so the data can be displayed. How do I do this, ngRoute, stateProvider, ... ?
You might be missing the point of angular if you ask this question. If your template has values which are bound to a model, then changing those values will automatically update the view on the next digest. It is possible that your asynchronous code (the request) does not trigger a digest, in which case you will have to do it manually. There are many ways to do that: digest and apply
One simple way is to inject $timeout, and do a zero duration timeout (no time argument) with the sensitive code in the body of the function you pass in
Edit: so to answer your question more directly, you should be storing your data somewhere in your application when the call succeeds, and then rely on the angularjs digest loop to update your view. That's one of angulars big work saving features.
Use $route.reload(); method to reload entire page after your successful Transaction, be sure to add dependency injection '$route' in your Controller.
I'm learning Angular I tried to init a controller after create a new content by ajax (with jQuery, maybe it's not a good idea but just I'm starting to learning step by step.)
this is my code.
angular.module('app').controller('TestController',function($scope){
$scope.products = [{
'code': 'A-1',
'name': 'Product 01'
}];
$scope.clickTest = function(){
alert('test');
}
});
$.ajax({..})
.done(function(html){
angular.element(document).injector().invoke(function($compile){
$('#content').html(html);
var scope = $('#content').scope();
$compile($('#content').contents())(scope);
});
});
In my html I use ng-repeat but not load nothing, however when I click in
ng-click="clickTest" it works! and ng-repeat is loaded. this is my problem I need that the ng-repeat load when I load for first time.
Thanks.
Sorry for my bad english.
with jQuery, maybe it's not a good idea
Yes spot on
Now getting into your issue:- When you click on element with ng-click on the html, it works because it then runs a digest cycle and refreshes the DOM and your repeat renders. $Compile has already instantiated the controller and methods are available and attached to DOM. But there is one digest cycle that runs in angular after controller initialization, which renders data in DOM, and that does not happen in your case since you are outside angular.
You could do a scope.$digest() after compile to make sure element is rendered and digest cycle is run.
Also probably one more better thing would be to wrap it inside angularRootElement.ready function, just to make sure before the injector is accessed the element is ready, in your case enclosing it inside ajax callback saves you (the time for it to be ready) but better to have it.
Try:-
$.ajax({..})
.done(function(html){
var rootElement = angular.element(document);
rootElement.ready(function(){
rootElement.injector().invoke(function($compile){
var $content = $('#content'),
scope = $content.scope();
$content.html(html);
$compile($content.contents())(scope);
scope.$digest();
});
});
});
Sample Demo
Demo - Controller on dynamic html
Instead of getting html from the server you could create partials and templates, use routing , use angular ajax wrapper with $http etc... Well i would not suggest doing this method though - however based on your question you understand that already. There was a similar question that i answered last day
If you are not looking for a better way to do what you are doing, ignore the following.
The beauty of using frameworks like AngularJS and KnockoutJS (or many more) is that we don't have to worry about the timing of when the data loads. You just set up the bindings between the controller and the UI and once the data is loaded into the respective properties, these frameworks will take care of updating the UI for you.
I am not sure why you are trying to set up the UI using JQuery and waiting for the data to loaded first to do so but normally you will not have to do all that.
You can create a UI with ng-repeat and click bindings ,etc and make an ajax call to get the data from anywhere. Once the data is loaded, in the callback, just push the necessary data into the collection bound to the ng-repeat directive. That is all you will have to do.
I'm learning AngularJs and I'm playing with a third party Javascript component.
At a certain point the control is initialized as follows:
$(document).ready(function () {
$('#SomeId').initialize();
});
Is there a way to convert this to something more Angularish? I don't want to manipulate the DOM from the controller, but I'm not sure how to initialize this.
This code is not necessarily wrong as is. What you want to be careful about is javascript outside of the angular context (jQuery callbacks/plugins etc) manipulating $scope values because those functions will not trigger an angular digest loop, and will result in a disconnect between the DOM and the $scope.
Here is some more information about this cycle and what you need to know about it: http://jimhoskins.com/2012/12/17/angularjs-and-apply.html
Here is a common use case with jQuery (and also why you should try to use angular services (ie: $http) instead:
// When you manipulate the $scope with a non-angular callback,
// you have to run $scope.$apply() to tell angular about the
// change in order to repaint the DOM
$.get( "/getUser", function( data ) {
$scope.user = data; // set $scope data in callback
$scope.$apply(); // run digest so anything in the DOM binded to the {{user}} model gets updated
});
Generally you don't need to manipulate the DOM like this with Angular...so you really don't need jQuery. Using an Angular "directive" is the declarative, encapsulated way to do it in Angular. There are a ton of 3rd party components out there for you to use that have been built properly with directives: I would recommend using these rather than trying to convert a jQuery plugin (which is really just adding the jQuery bloat for things that you already have access to with Angular). A good place to start looking for Angular directives that you can use is http://ngmodules.org/
I am using a basic API call to get an array of items to display in a table. My table loads perfectly fine, but I noticed that Angular is throwing a bunch of errors telling me that it can't interpolate expressions, etc.
I realized that this is because for the split second between page load and the API call response, Angular is trying to render the table and is obviously getting errors because the array used to populate the table does not exist yet.
Therefore, what is the standard way to get rid of this problem? Should I simply use ng-If or ng-hide to stop the render until the API call is complete or is there another way to tell angular to "wait" before rendering the DOM.
I was also able to fix this by initializing the array like $scope.dataArray = [], but I feel like this is a hassle when dealing with complex JSON objects that have many arrays and objects that need to be initialized.
Can someone please explain the best way to do this?
Another way this can be handled is using the resolve property on the router or state provider.
With ui-router's $stateProvider you can do this:
.state('mystate', {
controller: function($scope, data) {
$scope.data = data;
},
resolve: {
data: ['$http', function($http) {
return $http.get('/api/get-data');
}]
}
})
And the promise from the $http.get() will be resolved before the controller is instantiated. This works the same way using ngRoute.
$routeProvider (ngRoute) docs: https://docs.angularjs.org/api/ngRoute/provider/$routeProvider
video showing resolve: https://egghead.io/lessons/angularjs-resolve
another blog explaining resolve: http://odetocode.com/blogs/scott/archive/2014/05/20/using-resolve-in-angularjs-routes.aspx
The solution you've already come upon yourself is the correct one. Even if you are feeding Angular an empty scope variable or collection, that's all fine with the framework. What it won't accept is a complete null reference.
To avoid sullying your controllers, think about slurping up some some models into a parent controller, and nesting related objects, i.e. $scope.magic[], which contains $scope.magic.user, etc.
That's the gospel!
I have an existing angular project that has something really weird with the controller. It looks like the following.
app.controller('AppController', ['$scope', function ($scope) {
var app = app_application;
angular.extend($scope, app);
$scope.itTransports = app.state.itTransports;
}]);
I have a proof of concept for something I am trying to do on this fiddle and an attempt to mix the above controller and my concept in this fiddle but I cant seem to get it to work. I think it is something to do with the weird way the above controller works but I cant break it too badly and cant talk to the previous developer. I would think that if a combination cant be done then I would need some way for one controller to call another one but I want to make sure before I go down that path.
Edit: My main goal is to add functionality to check if the cookie exists. I am trying to do this in the same controller just for simplicity sake, but like I said before I am not adding a new one.
If you have some common functionality that you want to access from multiple controllers (e.g. checking if a cookie exists) then you should put that functionality into a service and inject that service into both controllers.