AngularJS ng-include does not include view unless passed in $scope - angularjs

Is it wrong to assume that ngInclude can take a raw path? I keep trying to set my ngInclude as follows:
<div ng-include src="views/header.html"></div>
This does not work but if I do something like this it does work.
// HeaderController
app.controller('HeaderCtrl', function($scope){
$scope.templates = {[
template: { url: 'views/header.html' }
]};
$scope.template = $scope.templates[0].template;
});
In my index.html
<div ng-controller="HeaderCtrl">
<div ng-include src="template.url"></div>
</div>
Does ngInclude only except values off of the scope? If so why is it this way and not a straight include of the html partial.

ng-include accepts an expression.
If you want to specify the explicit URL directly in there, you have to give a string.
<div ng-include src="'page.html'"></div>

ng-include, as other directives (ng-class, ng-src ...) evaluates an Angular expression from the scope. Without quotes (''), it will search for a variable of the scope.
Note that you don't have to specify the src attribute.
<div ng-include src="'views/header.html'"></div>
Can be rewritted to: (that is simpler)
<div ng-include="'views/header.html'"></div>
You can also use ng-include as an element:
<ng-include src="'views/header.html'"></ng-include>

Related

Angular JS : replace property in directive

In angular JS, we have a property called replace with possible values as true or false while defining directive. But i dont understand how this property will be used. Will it replace the HTML parent element when it is set true
Actual template:
<div class="parent">
<my-dir><div>Hello world!!</div></my-dir>
</div>
if replace is true, mir-dir tag will be removed.
<div class="parent">
<div>Hello world!!</div>
</div>
if replace is false, mir-dir tag will not be removed.
<div class="parent">
<my-dir><div>Hello world!!</div></my-dir>
</div>
Hope you understand!!. let me know if you have any queries.
Replace - If set to true will replace the element having a directive on it with a template.
PS : You have to use templateUrl/template along with replace.
HTML
<div angular></div>
<div class="angular"></div>
<angular>Simple angular directive</angular>
JS
var App = angular.module('App', []);
App.directive('angular', function() {
return {
restrict: 'ECMA',
replace: true,
template: '<img src="http://goo.gl/ceZGf"/>'
};
});
Above example angular directive will replace its contents "Simple angular directive" by contents in template i.e "Replaced content".
According to the documentation of angular (replace option):
true - the template will replace the directive's element.
false - the template will replace the contents of the directive's element.
Imagine you have a directive named my-directive with the template <span>directive</span> and your html code is <div my-directive></div>. Then replace : false results in:
<div my-directive><span class="replaced" my-directive="">directive</span></div>
And replace : true results in:
<span class="replaced" my-directive="">directive</span>
Please note that this option is deprecated.
See related questions:
How to use `replace` of directive definition?
Explain replace=true in Angular Directives (Deprecated)

Asynchronously issue

Use case:
In my index.html. I have two ng-include directives and two custom directives.
Each directive has its src attribute defined the address to load some html snippet from another server (the custom directives have its template attribute loading the html)
I need to make sure that all directives (see the code 1,2,3) have fully loaded the html snippets before I call the fifth ng-include directive (4) to load the java-script from another server.
Right now all directives are running asynchronously and I can't be sure that the directive which loads the Javascript should always be the last one to load. I need this because if Javascript is loaded and executed before the html it wouldn't go through the html and linking it to javascript/jQuery.
I have solved this issue using a very classic way. I update a global variable whenever the html snipts are loaded and define the an ng-include directive to load the Javascript conditionally when the global variable is true indicating all other directives have loaded their html. But this is not the Angular way. I need the Angular way and btw I'm new starter on Angular.
Index.html
<div ng-controller="navigationController" >
**(1)**<agilesites-navbar></agilesites-navbar>
<div class="container-fluid">
<div class="row row-offcanvas row-offcanvas-right">
<div id="offcanvas-curtain" class="hidden-lg"></div>
<div id="contentContainer" class="col-sm-12 col-md-12 col-lg-12">
<div ui-view="content" id="content"></div>
</div>
**(2)**<agilesites-sidebar></agilesites-sidebar>
</div>
</div>
**(3)**<ng-include src="''+API_HOST+'api/cms/footer'" onload="cmsResourceLoadingStatus(true)"></ng-include>
**(4)**<ng-include src="''+API_HOST+'api/cms/javascript'" ng-if="cmsResourceLoadingCompleted"></ng-include>
</div>
Custom directive (agilesites-sidebar):
angular.module('newhorizonsApp')
.directive('agilesitesSidebar', ['ProductTypes','$compile', function (ProductTypes,$compile) {
return {
restrict: 'E',
scope: true,
template: '<ng-include src="\'\'+API_HOST+\'api/cms/sidebar\'" onload="executeOnLoad();"></ng-include>',
link: function (scope,elem){
scope.executeOnLoad = function() {
scope.cmsResourceLoadingStatus(true);
};
}
};
}]);

using ng elements outside of ng-controller

I am inexperienced with angular.
I am using angular to create a series of nested divs (a form) on a webpage. The top div has ng-controller="controllername" as an attribute. Within the nested divs is a div with ng-show="showvar" as an attribute.
It looks like this.
<div class="page">
<div ng-controller="controllername">
<div ng-show="showvar">Hidden Stuff</div>
</div>
</div>
When I perform functions on showvar to make it true, the div appears (and disappears when false) as intended.
I also have a completely separate div 'outside' the the original nest of divs with the ng-controller attribute. As such, there is no ng-controller attribute in this seperate hierarchy BUT I have nested another div inside with the ng-show="showvar" attribute.
Updated HTML structure is as such
<div class="page">
<div ng-controller="controllername">
<div ng-show="showvar">Hidden Stuff</div>
</div>
<div class="seperate">
<div ng-show="showvar">More Hidden Stuff</div>
</div>
</div>
When the page loads, both divs with ng-show="showvar" in the separate nests are hidden as ng-hide has been appended by angular. When I perform functions on showvar after the page load to make it true, only the div within the ng-controller div gets shown.
I (think I) understand this is because the ng elements are evaluated at page load (and appended with ng-hide, even outside the controller?) but only the ng elements within the div with the ng-controller attribute are evaluated when functions are performed after page load. Is this correct?
How can I get the other ng-show to be evaluate 'outside' of the ng-controller div?
I was thinking one option is to append ng-controller to the overall 'page' div instead of the nested div. But what other options do I have?
EDIT: I also tried simply adding ng-controller="controllername" to the separate div. I guess angular 'ignores' the duplicate ng-controller div?
The problem your facing is that the showvar resides in your controller's scope, your second usage of the showvar is not within that scope.
What you need to do is make sure the variable is available where needed.
Say you add the variable to the parentController (you don't have one in your example so I'll add one)
<div class="page" ng-controller="parentController">
<div ng-controller="controllername">
<div ng-show="showvar">Hidden Stuff</div>
</div>
<div class="seperate">
<div ng-show="showvar">More Hidden Stuff</div>
</div>
</div>
app.controller('ParentController', function($scope){
$scope.showvar = false;
});
problem with this is when you set showvar to true within your controllername controller it will set it in the innerscope and not the outer. When making sure you have the right scope by accessing it through another object you should be safe.
So try it like this:
<div class="page" ng-controller="parentController">
<div ng-controller="controllername">
<div ng-show="obj.showvar">Hidden Stuff</div>
</div>
<div class="seperate">
<div ng-show="obj.showvar">More Hidden Stuff</div>
</div>
</div>
app.controller('ParentController', function($scope){
$scope.obj = {
showvar: false
}
});
Quick demo
Your issue here is that you ended with 2 "showvar" variables: one within the "controllername" scope and another one on the app scope (as you have a ng-app declaration somewhere in your html parent of the "page" div).
When you load your page, you get the value of "showvar" in the controller scope for the first div, and for the "separate" one, you get the "showvar" variable in the app scope, which doesn't exist, therefore it is resolved to "false" (even though angular declares it for you in your app scope and you can even modify its value later).
When you change the value of "showvar" in the controller scope, it doesn't change the one in the app scope, making the "separate" div stay hidden forever =)

ng-repeat with ng-include not working

I am trying to use an ng-repeat that includes an ng-include. The problem is that the first element in the ng-repeat is just the ng-include template with none of the data from the ng-repeat filled in. Is there a way I can somehow bind the template from the ng-include so it works on the first ng-repeat?
<div ng-repeat="item in items">
<div ng-include src="'views/template.html'"></div>
</div>
For example, if my ng-repeat contains 10 items, then the first item that is rendered will just be the empty template. Items 2-10 WILL be rendered as they should be. What am I doing wrong?
First make sure that the data that is contained in the first index of items actually has the data that you want.
One possible solution to your problem would be to simply not show the first index of the ng-repeat:
<div ng-repeat="item in items" ng-show="!$first">
<div ng-include src="'views/template.html'"></div>
</div>
This may not actually tackle the root of your problem, but it may still get your application working a bit more like what you expect.
Another possible solution:
<div ng-repeat="item in items" ng-include="'views/template.html'"></div>
see example here:
http://plnkr.co/edit/Yvd73HiFS8dXvpvpEeFu?p=preview
One more possible fix just for good measure:
Use a component:
html:
<div ng-repeat="item in items">
<my-include></my-include>
</div>
js:
angular.module("app").directive("myInclude", function() {
return {
restrict: "E",
templateUrl: "/views/template.html"
}
})
I ran into the same problem, and finally figured out that the first element has not been fetched and compiled in time for the first ng-repeat iteration. Using $templateCache will fix the problem.
You can cache your template in a script tag:
<script type="text/ng-template" id="templateId.html">
<p>This is the content of the template</p>
</script>
Or in your app's run function:
angular.module("app").run(function($http, $templateCache) {
$http.get("/views/template.html", { cache: $templateCache });
});
You can also use $templateCache inside your directive, although it's a bit harder to setup. If your templates are dynamic, I would recommend creating a template cache service. This SO question has some good examples of template caching inside a directive and a service:
Using $http and $templateCache from within a directive doesn't return results
Using a directive worked for me: https://stackoverflow.com/a/24673257/188926
In your case:
1) define a directive:
angular.module('myApp')
.directive('mytemplate', function() {
return {
templateUrl: 'views/template.html'
};
});
2) use your new directive:
<mytemplate />
... or if you're concerned about HTML validation:
<div mytemplate></div>

Is it possible to use a function to insert the template path for ng-include?

I have tried to use a function to load the path to a template into an ng-include directive. I hoped that the argument to my function would render due to its insertion in ng-include. But it doesn't work. Here is what I have so far:
HTML:
<div ng-include="'{{content}}'"></div>
...
<div ng-click="showContent('views/my_content.html')">
Angular:
$scope.showContent = function(attrs){
$scope.content = attrs;
};
When I click on the div that has ng-click I can see that {{content}} has been replaced with the template path, but the template itself is not included (i.e., it is not rendered on the page). Is there a way that I can force the template to render?
Instead of this
<div ng-include="'{{content}}'"></div>
use this
<div ng-include="content"></div>
and the template would get rendered.
ng-include does not work like this.
What you need to do is either write another directive that will fetch and show content for you. You could also use $routeProvider to change the url and have it include a template URL.

Resources