Due to the structure of an existing project I'm working on, I'm stuck with a template that looks like this:
<div ng-app="example">
<div ng-controller="MainCtrl" id="inner">
{{ inside }}
</div>
</div>
<div ng-controller="MainCtrl" id="outer">
{{ outside }}
</div>
#outer is supposed to be using the same controller as #inner, but as it's located outside of ngApp's scope, {{ outside }} will not be evaluated. Unfortunately I can't change the template structure, so I tried to compile #outer's content like this:
app.run(function($rootScope, $compile){
$rootScope.$apply($compile(document.getElementById('outer'))($rootScope));
});
This works, but the controller function will be executed twice, which is not desired. Is there a better way to achieve my goal?
Working example on Plunker
what you could do instead, is NOT define ng-app at all in the html, and instead bootstrap angular via javascript.
for example you can do angular.bootstrap(document, ['example']); where 'example' is the angular module for the app for example angular.module('example', [
'ngResource', 'ui.router', ....
]);
you probably defined that yourself already.
This way, you define the ng-app on the entire document scope.
That is normal, you're initializing twice the controller. You could simply create another div, wrapping all the divs you want and use alias. But this will still initialize twice, but each div will have different values, like, {{inside}} on first div will not have the same as the second one has.
<div ng-app="example">
<div>
<div ng-controller="MainCtrl as FirstCtrl" id="inner"> // alias FirstCtrl
{{ inside }}
</div>
</div>
<div ng-controller="MainCtrl as SecondCtrl" id="outer"> // alias SecondCtrl
{{ outside }}
</div>
</div>
But if you intend to use just once the same controller, as far as I'm concerned, you'll have to wrap all divs you want to use the same controller, in just one div, like:
<div ng-app="example" ng-controller="MainCtrl">
<div id="inner">
{{inside}}
</div>
<div id="outer">
{{outside}}
</div>
</div>
This will initialize just once.
Other way, could be attaching ng-app and ng-controller in your html/body tags.
Related
I'm using DayPilot Scheduler in my app and i'm having the following issue.
home.html:
<div class="container-fluid">
<daypilot-scheduler id="scheduler" daypilot-config="schedulerConfig" daypilot-events="events"></daypilot-scheduler>
</div>
I access daypilot scheduler in my controller like this:
$scope.scheduler;
This works when daypilot directive is directly inside home.html like in home.html above, but returns undefined when I include daypilot with ng-include:
<div class="container-fluid">
<div ng-include src="'partials/partial1.html'"></div>
</div>
partial1.html:
<section>
<daypilot-scheduler id="scheduler" daypilot-config="schedulerConfig" daypilot-events="events"></daypilot-scheduler>
</section>
If it's included with ng-include, $scope.scheduler returns undefined. scheduler is placed under $$childTail as $$childeTail.scheduler.
What am I doing wrong, and how can I access $$childTail?
Try adding $parent. prefix to id attribute's value. So partial1.html will be:
<section>
<daypilot-scheduler id="$parent.scheduler" daypilot-config="schedulerConfig" daypilot-events="events"></daypilot-scheduler>
</section>
And in controller access it like you always did:
$scope.scheduler;
This works:
<div ng-include="'login.html'" flex ng-if="!loggedIn" ng-controller="LoginController"></div>
However, this doesn't ({{test}} outputs nothing):
<ng-include src="'login.html'" flex ng-if="!loggedIn" ng-controller="LoginController"></ng-include>
Is there any reason? Or is it a bug?
login.html:
<p>{{test}}</p>
LoginController:
function LoginController($scope){
$scope.test = 'login';
}
I'm not exactly sure where "loggedIn" is defined, but when I define it on a parent controller, both syntaxes work as expected.
Plunkr
<div ng-controller="PrntCtrl">
<div ng-include="'test.html'" flex ng-if="!loggedIn" ng-controller="TestCtrl"></div>
<ng-include src="'test.html'" flex ng-if="!loggedIn" ng-controller="TestCtrl"></ng-include>
</div>
Some questions to consider:
What version of angular are you using?
How is your app defined and how is the controller registered with the app?
Where is "loggedIn" defined?
Because this directive accepts only 3 arguments:
ngInclude | src = string
onload (optional) = string
autoscroll (optional) = string
...according to the ngInclude Docs
EDIT:
you can solve simply wrap it in another element...
<div ng-if="!loggedIn" ng-controller="LoginController">
<div ng-include="'login.html'" flex></div>
</div>
Here is a Plunker: http://plnkr.co/edit/F6QM4KUU8DPNq6muInGS?p=preview
Including an html file with ng-include, having set the ng-controller in the same tag, doesn't update the controller's scope models. Using the ng-model directly inside of the html works perfectly fine, and also setting the controller inside of the included html file is working. But ng-include together with ng-controller $scope.models don't update and stay as they are.
For whatever reason if you set the model inside of the controller, it is done suring it's loading. But having a method setting the model (not included in the plunker) only changes the mdoel inside of the controller's scope and not the html one.
Also if I use an ng-include in the scope of another controller and want to access the included models return undefined or the value you set the model to. Calling methods from the included html works fine in both cases, but they can't really operate as the values are wrong.
I saw that a similar issue has already been postet and should have been resolved (https://github.com/angular/angular.js/issues/4431), but as you can see in the plunker for me it doesn't.
Do I miss something, or is this a problem of angular?
Kind Regards,
BH16
PS: Here is the code from the Plunker:
index.html - body
<body ng:controller="MainCtrl">
<input type="text" ng:model="input">{{input}} {{getInput()}}
<div ng:include="'main2.html'" ng:controller="Main2Ctrl"></div>
</body>
main2.html
<div>
<input type="text" ng:model="input2">{{input2}} {{getInput2()}}
</div>
script.js
angular.module('testApp', [])
.controller('Main2Ctrl', function($scope) {
$scope.input2 = 1234;
$scope.getInput2 = function() {
console.log("input2");
return $scope.input2;
};
})
.controller('MainCtrl', function($scope) {
$scope.input = 1234;
$scope.getInput = function() {
console.log("input");
return $scope.input;
}
});
For all of those who are are also having this issue: Just use the controllerAs syntax: http://toddmotto.com/digging-into-angulars-controller-as-syntax/
This solves all of the issues above and simplifies the code A LOT!
This is the basic idea of controllerAs (taken from the site above):
<div ng-controller="MainCtrl as main">
{{ main.title }}
<div ng-controller="AnotherCtrl as another">
Scope title: {{ another.title }}
Parent title: {{ main.title }}
<div ng-controller="YetAnotherCtrl as yet">
Scope title: {{ yet.title }}
Parent title: {{ another.title }}
Parent parent title: {{ main.title }}
</div>
</div>
</div>
It's related to that ng-include creates it's own scope.
To see what's actually happens you can try plugin(for google chrome, probably something similar exists for others browser's too): "AngularJS Batarang", it will include additional tab to dev tools.
And possible solution will be:
main2.html:
<div ng:controller="Main2Ctrl">
<input type="text" ng:model="input2"> {{input2}} {{getInput2()}}
</div>
http://plnkr.co/edit/daIehNjxWdam3NyH3ww4?p=preview
I am including a view using the ngInclude directive. The included view has properties that binds values to $scope.model. This is a problem, since the parent scope is using $scope.model. What i need to do is to "reroute" the included views $scope.model to the parent scope's property $scope.include1.model. How can i do this "scope reroute" the way i want to?
Here is an example showing my problem
<div ng-controller="myCtrl">
<div ng-include="'input.html'"></div>
<div ng-include="'input.html'"></div>
</div>
<script type="text/ng-template" id="input.html">
<div ng-controller="childCtrl">
<input type="text" ng-model="model"/>
</div>
</script>
As you can see i have two includes to the same view, and both input text boxes will be bound to the same value. I want to bind them to different values in myCtrl
I can't make any changes to either my childCtrl or the included view.
You can try this
<div ng-include="'input.html'" ng-init='model=include1.model'></div>
<div ng-include="'input.html'" ng-init='model=include2.model'></div>
I have the following code:
<div ng-repeat="item in items">
<div ng-include src="itemG.html"></div>
</div>
then in itemG.html I have:
<img src="{{item.image}}">
How can I get my ng-repeat to print out all of the images?
There are 2 potential problems in the code...
src="itemG.html" needs an extra pair of single quotes like this:
<div ng-repeat="item in items">
<div ng-include="'itemG.html'"></div>
</div>
And the img tag is missing a closing ":
<img ng-src="{{item.image}}">
Plunker: http://plnkr.co/edit/7IUs7WPdUYkfVVKtBN1m?p=preview
Basically, what this comes down to is that the browser will interpret what inside the src attribute literally, until angular comes along to replace it. If you have a string constant, you can use single quotes inside the src="'myurl.html'", but if you have a value that needs to be bound by angular, you have to use ng-src and the expression syntax of {{ }}
You also need to bind a model to your template file itself. It's not going to pick up the bindings from your repeater without some help from either the ng-include event directives, or it's own model/controller/directive. There are too many different ways to demonstrate that, and it's also relevant on what markup is in your template file, which I can't say.
However, if the img tag is the only thing in that file, then instead of the file, I'd just do this:
<div ng-repeat="item in items">
<img ng-src="item.image" />
</div>
Since you're inside a repeat, it's already being included, making the ng-include redundant.
In principal code
<div ng-repeat="item in items">
<ng-include src="itemG.html" ng-controller="MyCtrl" ng-init="i=item"><ng-include>
</div>
then in itemG.html I have:
<img src="{{i.image}}">