Angularjs : how to load data on a partial? - javascript

I am working with Angular and i am trying to update data of a ng-view when we click on the button but it's not working. Here my code snippet.
main page
<body ng-app="app">
<div ng-controller="MyController" >
Load datas
<div ng-view></div>
</div>
</body>
The ng-view:
<div>
{{myValue}}
</div>
<div>
<li ng-repeat ="data in datas">
{{data.name}} || {{data.value}}
</li>
</div>
The loadDatas function :
$scope.loadDatas = function(){
$http.get('data.json')
.then(function(res){
$scope.datas = res.data;
});
};
I want to load datas when the link is clicked.But it's not working. I have a plunker here if someone could help me.
Thanks

1)
Since it's an async call, the easiest way would be to wrap the var change in a $timeout callback:
$scope.loadDatas = function(){
$http.get('data.json')
.then(function(res){
$timeout(function(){
$scope.datas = res.data;
}, 0);
});
};
This basically forces a scope digest without you having to worry about the digest phase. Of course, don't forget to inject $timeout into the controller.
If you still want to do the digest manually, you can do $scope.$apply().
2)
You also need to fix your JSON as I have shown how you in the comments:
{"name":"Dan","value":"13"},
{"name":"John","value":"34"},
etc...
3)
No need to assign the same controller twice.
Specifying the controller in the route cause the controller to spawn a new scope (and plus one each time that anchor is clicked, unless you remove the href attribute or block it in another way). I fixed it by removing the controller directive:
when('/', {
templateUrl: 'partial.html'
}).
So, there was no need to specify a controller unless it's a different controller than the one the ng-view is inside of. In your case, that was not the case (you only used a controller that the view is already in) and it was causing two different controllers/scopes (even more if the href attribute is present in the anchor when you click it) to spawn and $scope.datas in one scope is not the $scope.datas in the scope that was bound to the partial.
A different variable name would work because of the scope parent/child inheritance; so if the variable names don't match, a parent scope variable would be available in the child scope without specific definition.
Here is the working version: http://plnkr.co/edit/QWPFAakvNEdJzU50LKSx?p=preview

You forgot to inject the $http in your controller:
app.controller("MyController", function($scope, $http) {
Take a look at this one: var name changed plnkr.

Related

angular - append and execute script inside ng-view before append the template content within it

Since script can't be loaded inside templates, due to Angular's jQLite wasn't written to achieve it, I decided to add jQuery library before Angular since it checks for jQuery existence, and voila!, it works. But, the fact that I'm here asking a question, means that there's a 'but', so, the script doesn't execute before content loads. Of course, I made a little trick with routes.
In module's config section, I made this:
$routeProvider
.when("Business/:Context/:View?", {
templateUrl: function (url) {
return "Contexts/" + url.Context + "/" + (url.View || url.Context) + ".html";
}
});
Then let's say we set the route to "#/Business/Test" he most locate a file called Test.html on "/Contexts/Test", right eh!. Let's say Test.html content is this.
<script>
(function(ng){
console.log(ng)
ng.module('MyApp').controller('TestController', function ($scope, $route, $routeParams, $location, $http, $mdDialog) {
$scope.name = "TestController";
$scope.params = $routeParams;
$scope.name = "John";
});
})(angular)
</script>
<div ng-controller="TestController">
Hola {{ name }}
</div>
And finally the real question: why is this happening? It's like the is executed after or I don't know, because, looking the console:
Angular exists but the controller isn't added in time.
Am I doing wrong? It this behavior allowed? Can anyone lead me in this trip?
Are you trying to include the controller script with the view? Don't understand why and what the logic behind it? You have the template and the controller and the reason is to separate the view/DOM and the business logic behind it.
In angular, the script tag Load the content of a element into $templateCache, so that the template can be used by ngInclude, ngView, or directives so it doesn't interpulated the same as a <script> tag would be normally loaded.
They also state that The type of the element must be specified as text/ng-template, and a cache name for the template must be assigned through the element's id, which can then be used as a directive's templateUrl.
So you're just not using the script tag as intended by angular.
Why not including the controller in a js file and load it from the root HTML, or by using requirejs or a similar library.

Issues with AngularJS Controller

I have the following setup in my html file:
<body>
<nav ng-controller="loginCtrl">
<div>
<li>Apple</li>
<li>Mango</li>
<li>{{user}}</li>
</div>
</nav>
<div ui-view></div>
</body>
I have a navigation menu and the ui-view that displays different pages.
I also have a controller, loginCtrl, with a scope variable called $scope.user. This controller is also called in the UI-state router for the login.html file as well so that the login form can use its methods.
When a user logs in, I want to show his name in the navigation menu using the {{user}} above. The navigation menu as you can see is visible (static) regardless of other partial pages that will be loaded in the ui-view.
At the moment, it is not working and I don't know why.
My understanding is that the login form in the login.html and the navigation menu are in different files so that may be they are using the same controller (under the same module) yet may be operating in different scopes/environments (am not really sure about that).
That is why I update the value of $scope.user but it doesn't appear in the navigation menu.
Why is it not working and how can I achieve my functionality?
Using a singleton service to share same UserData object:
app.service('UserData', function(){return {name: 'default'};});
app.controller('LoginController', function($scope, UserData){
$scope.user = UserData;
});
Now, all controller instances have access to same UserData object.
When user.name has changed, all controllers can see it.
I'm wondering if it's necessary to cal your LoginController for your ui-view and a sibling element, when you could load it on a parent element
Anyway, you have several solutions to make the two-way binding work:
#vp_arth solution is really great, usually used this to share data between controllers
Move your ng-controller attribute to a common parent element, and if needed, declare another controller for your login.html, that will be a child of your LoginController. Then use an object instead of a variable in your parent scope:
$scope.user = {};
and then fill it in your child scope like this:
$scope.user.name = ...
Even if you're using the same controller as parent AND child scope, you should make this work with something like this:
$scope.user = $scope.user ? $scope.user : {}; instead of $scope.user = {};
(if it's not clear I can make a comparative fiddle to show you)
This wiki really helped me when I had issues like yours: https://github.com/angular/angular.js/wiki/Understanding-Scopes

Why does my $watch only ever fire once?

I'm factoring out some widget and the $watch expression works perfectly having all in one file but now I moved the relevant controller part into a new controller and the markup into a new html and the $watch fires exactly once after initialization but not when editing typing in the associated input.
JS:
app.controller('getRecipientWidgetController', [ '$scope', function($scope) {
console.log("controller initializing")
var testReceivingAddress = function(input) {
console.log("change detected")
}
$scope.$watch("addressInput", testReceivingAddress)
} ])
HTML of wrapper:
<ng-include
src="'partials/getRecipientWidget.html'"
ng-controller="getRecipientWidgetController"
ng-init="recipient=cert"> <!-- ng-init doesn't influence the bug. -->
</ng-include>
HTML of partials/getRecipientWidget.html:
<md-text-float ng-model="addressInput"></md-text-float>
I suspect there is some scope voodoo going on? I left the ng-init in to make clear what I want to achieve: build an obviously more complex, reusable widget that in this instance would work on $scope.cert as its recipient.
That is probably because ng-include will create a new inherited scope on the included HTML, hence $scope.addressInput in your controller is not the same reference as $scope.addressInput in getRecipientWidget.html
Well it's not easy to explain, but you should either put ng-controller within the HTML of getRecipientWidget.html (and not on the div above that includes it), OR you can use an object such as something.addressInput instead of the raw addressInput which avoids references issues on raw types (number/string).
ng-include creates new scope.
Try this
<md-text-float ng-model="$parent.addressInput"></md-text-float>
Plunker example

Angular adding a body class depending on state

I have something like this working
<body ng-app="ELT" ng-class="{'mapBody': $state.includes('map')}" ng-controller="mainCtrl">
So obviously what I am trying to do is add a class "mapBody" when the state is map
and my controller a such
.controller('mainCtrl', ['$scope','$state',function ($scope,$state) {
'use strict';
$scope.$state = $state;
}])
Is there a better way to do this ? Don't like the fact I had to had a new controller just for this one thing, plus it's a lot of logic in the html.
As per Radim Kohler Better way is, you could use the ui-sref-active directive.
To add the class active to your element when the ui-router state matches use
HTML
<body ng-app="ELT" ui-sref-active="mapBody" ng-controller="mainCtrl">
<a ui-sref="app"></a>
</body>
Whenever underlying ui-sref is current state then if will apply mapBody class to body.
See Example here
Edit
In your case you want to append a class to body depending on state,
So using ui-sref-active in this case will not work. Because body can contain several ui-sref and at least one will be satisfied, class will always append to body.
I believe currently the way you are doing is correct.
But I'd like to suggest one change,
instead of assigning $state to controller each time. Do it in angular run phase only once.
//it will assign a state inside $rootScope and it will get available on each page
app.run(function($rootScope, $state) {
$rootScope.$state = $state;
});
Above code will be more cleaner and it will avoid assigning $state inside scope each time.
Thanks.

AngularJS directive only called once?

I'm trying to shove mixitup inside my angular page and in order to do so I made a directive module for it
angular.module('MainCtrl', [])
.controller('MainController', function($scope) {
$scope.tagline = 'To the moon and back!';
})
.directive('mixitContainer', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
$(element).mixItUp(scope.$eval(attrs.mixitContainer));
}
};
});
Don't worry about the simplicity of the main controller, it is simply a test.
Now, the issue is that the directive only get's called once! If I go to another page and ask angular to load another controller and then go back to the home page and ask angular to load MainCtrl again, the directive isn't loaded!
Heres the with the directive:
<div id="Container" class="mixit-container" mixit-container="{load: {sort: 'order:asc'}, controls: {toggleFilterButtons: true, toggleLogic: 'and'}}">
Anyone got any ideas?
AngularJS doesn't include routing facilities. Those are provided either by ngRoute (a core but optional module), ui-router (ngRoute made super-awesome-amazing), or another replacement. You don't say which you use, and each has different behaviors.
Whichever it is, this is going to come down to the router, not the directive. The directive will get called whenever necessary. It doesn't control that itself - 'necessary' means Angular is compiling a portion of the DOM, usually from a template file, and has run into the directive. It will call the directive and ask it "what now?"
The above-named routers have different behaviors, both from each other and also based on how you configure them internally. In all of them you can arrange things so that templates do, or do not, get re-rendered. For example, in ui-router you can have 'child' states. If you have a child state active, the parent is also active... so going from the child to the parent will not re-render a template because it was already done earlier. And to make matters more complex, you can even override this by hooking the $stateChangeStart event and force the router to redraw that view even if it didn't think it needed to.
All this means... set your attention to your directive aside. It will do what you want as soon as the higher level does what you want. Get your router behaving the way you expect and you will be happy!

Categories

Resources