Multiple ng-init scope issues - javascript

I'm trying to use ng-include with ng-init to re-use the same component by only changing its data.
The component code ("slider.html", which has no controller) looks like this:
<div ng-repeat="person in persons">
{{person.name}}
</div>
From the main view, I want to reuse the same component changing "persons" list so in the view I have:
<!--slider #1 -->
<div ng-init="persons=english" ng-include ="'inc/app/views/widgets/slider.html'"></div>
<!-- slider #2 -->
<div ng-init="persons=german" ng-include ="'inc/app/views/widgets/slider.html'"></div>
and in the controller I initialize the 2 lists "english" and "german" like this:
$scope.english = records.filter(function(t){return t.nationality=="english";});
$scope.german = records.filter(function(t){return t.nationality=="german";});
What happens is that the 2 components shows the same list of data (german); is there a way to bind the 2 different sets to the components?

That (having both lists being set as German) happens because, at the end, you are only using one controller, which has only one scope in which the persons varaiable exists. When AngularJS starts its bootstrapping process, it processes the first ng-init, updating the current controller's persons variable to English. Then it processes the second ng-init, updating again the same persons variable now to German. Then, when the ng-repeat is rendered, it will take the current and unique persons variable data, hence, being everything in German.
What you can do is to have an independent controller per component (slider.html), so each controller will have its own binding variables so you can create a persons variable for each one and initialize every controller's variable independently with your ng-init directive. Example:
<div ng-controller="MySubController" ng-repeat="person in persons">
{{person.name}}
</div>
...
<!--slider #1 -->
<div ng-init="initMySubController(english)" ng-include ="'inc/app/views/widgets/slider.html'"></div>
<!-- slider #2 -->
<div ng-init="initMySubController(german)" ng-include ="'inc/app/views/widgets/slider.html'"></div>
In a JS file:
var myApp = angular.module('myApp',[]);
myApp.controller('MySubController', ['$scope', function($scope) {
$scope.persons = [];
$scope.initMySubController = function(personsData) {
$scope.persons = personsData;
}
}]);

Related

AngularJS loads constructor multiple times

my controller is loaded multiple times in my AngularJS 1.5 code:
<div ng-repeat="conditionForMultipleRows">
<div data-ng-if="$first">
<div co-my-component></div>
</div>
</div>
export function coMyComponent(): ng.IDirective {
return {
template: coMyComponentTemplateHtml,
controller: 'MyComponentController',
controllerAs:'$ctrl'
}
}
export class MyComponentController{
state: MyStateClass;
static $inject = [someServices]
constructor(someServices) {
document.getElementById("myComponent").addEventListener("myEvent", (ev: CustomEvent) => {
doStuff()
}
The HTML Part is only called once, so there should be no issue. Only my controller is loaded multiple times.
The angular.module only loads the controller once and the directive only once, so there is no issue. Also there is no other place where the controller or webcomponent is called in the code.
I'm not very familiar with AngularJS so you can also point out other parts if you see something wrong here. Please refer to a source if it was resolved there. I didnt find any helpful answer
Thanks in advance guys
Each time your directive is instantiated, it will received a brand new controller.
The ng-repeat directive instantiates a template once per item from a collection.
In your case, if conditionForMultipleRows is an array having four items inside, you will instantiate four times the template
<div data-ng-if="$first">
<div co-my-component></div>
</div>
Each template instance gets its own scope and own controller, thus calling the constructor four times.
The answer for my issue here is:
<div ng-repeat="conditionForMultipleRows track by $index ">
<div data-ng-if="$first">
<div co-my-component></div>
</div>
</div>
With adding track by $index, the controller of my component only loaded once.
Also learned that in a ng-repeat it should always be added a "track by". There are only a few egde cases where this isnt required. Correct me if I'm wrong

Controller constructor called more than once

I have a simple controller
angular.module('datahubApp')
.controller('LoginController',[ '$scope' , '$resource', LoginController]);
function LoginController($scope,$resource){
console.log('Constructor called');
}
I have used the this in HTML in 2 places for two different components, in the same view
<div ng-controller="Logincontroller as ln"> </div>
<div ng-controller="Logincontroller as ln"> </div>
Now when I run the app, i see this in console
Constructor Called
Constructor Called
Constructor Called
Question 1:
So, this is getting called thrice. Is this normal.
Question 2:
In that case, how can I pass the scope variable between components?
Why are you using same controller two times in a view. Use it one time only and it would work perfect.
You can use like:
<div ng-controller="Logincontroller as ln">
<div></div> <!-- Your first div -->
<div> </div> <!-- Your second div -->
</div>
AngularJS will call a controller every time it found in a view. No matter how much time is there in view part.

Angularjs parent scope use the child scope'attribute

angular.module('myApp',[])
.controller('Parent',['$scope',function($scope){
//define nothing
}]).controller('Child',['$scope',function($scope){
$scope.user={username:''};//define an object user
}])
<div ng-app="myApp">
<div ng-controller="Parent">
{{user}}<!--print nothing-->
<div ng-controller="Child">
{{user}} <!--print an object-->
</div>
</div>
</div>
How to deal with the problem above without using the inject of $rootScope
Based on your comment...
i want the parent user print the value of child user without using $rootScope
... you can't accomplish this because the parent scope cannot inherit from the child scope as it is currently defined. View controllers inherit from their parent controllers based on their node structure.
<parent-node>
{{user.name}}
<hr/>
<child-node>
<!-- user inherit from parent node's scope by default -->
{{user.email}}
</child-node>
<another-child-node>
<!-- user inherit from parent node's scope by default -->
{{user.someOtherData}}
</another-child-node>
You either need to define the user on your parent scope like so:
.controller('Parent',['$scope',function($scope){
$scope.user = {};
}])
.controller('Child',['$scope',function($scope){
}])
... or you can handle this via a directive depending on the end User-eXperience.
This is a problem that returns when people use $scope without reading up on the scopes documentation.
This is why I always tell people not to use $scope to bind objects / functions to. Well this and maintainability.
CONTROLLERS:
angular.module('myApp',[])
.controller('Parent',['$scope',function(){
//define nothing
}])
.controller('Child',['$scope',function(){
this.user = {username:''}; //define an object user
}]);
TEMPLATE:
<div ng-app="myApp">
<div ng-controller="Parent as parentCtrl">
{{ parentCtrl.user }} <!-- undefined -->
<div ng-controller="Child as childCtrl">
{{ childCtrl.user }} <!-- object -->
</div>
</div>
</div>

How to pass an item from ng-repeat to a controller created/loaded by ng-include?

I have an ng-repeat that loads an ng-include. I'd like to have a separate controller inside the view that the ng-include loads.
But I'm having trouble accessing the item from ng-repeat in that controller. I tried something like this, and it fails.
How do I get at result inside of SubController?
<div ng-repeat="result in results">
<div class="box" ng-include="view/someinclude.html"></div>
</div>
view/someinclude.html:
<div ng-controller="SubController">
...
</div>
controller js:
angular.module('SubController', [])
.controller('SubController', ['$scope',
function ($scope) {
//fails
console.log($scope.result);
}
]);
Make sure your scopes are a part of the same module, or they they're different include one in the other, if that's not the problem then it'll be something outside what you've shown, as something like this:
angular.module("app").controller.(testController", ["$scope", function($scope){
console.log($scope.x)
}])
with:
<div ng-repeat = "x in [1,2]">
<div ng-include = "'./views/vew.test.html'">
</div>
</div>
and in vew.test.html:
<div ng-controller = "testController">
{{x}}
</div>
Will wack 1 and 2 on the screen and in the console.
Make sure you're using the same module:
angular.module('SubController').controller('SubController', function() {...});
Try using $parent.result instead of $scope.result inside your controller as ng-include creates a new scope of its own that prototypically inherits from its parent scope.

How to change to a different view from controller in AngularJs

I'm retrieving a person from a service and displaying the details on the details.html template. If the person is not found, the service returns a 404 response and I handle it from within the controller by (currently) displaying an alert popup stating its not found.
Is it possible to dynamically change to a different template, like a 'notfound.html' for instance?
You can do it using ng-switch directive. Save state of your request in variable (for example $scope.items = data if you received your data correctly or $scope.items = false otherwise) and then:
<div ng-switch on="items">
<div ng-switch-when="false" ng-include src="'error.html'"></div>
<div ng-switch-default ng-include src="'details.html'"></div>
</div>

Categories