AngularJS - load dynamic template HTML within directive - angularjs

I have a directive which loads content from an external HTML file. Passed into this directive is some scope data which is used in the rendering of that HTML fragment. e.g.
<div class="{{cls}}" data-obj="{{obj}}" data-id="{{id}}">
<!-- remainder of content here -->
</div>
What I would like to do within this directive is to load a further HTML partial within this based on the original scope data passed into the directive. I can't seem to get this to work, but it should be something along the lines of the following:
<div class="{{cls}}" data-obj="{{obj}}" data-id="{{id}}">
<!-- remainder of content here -->
<div ng-include="partials/{{obj}}.html></div>
</div>
Using this, the file doesn't get included, but I don't get any errors either. Can anybody assist me here?
NB: I read this, which is a similar issue, but hasn't helped me.
UPDATE - I noticed in Chrome dev tools that the URL is being resolved as expected, but the file contents are not getting included. I thought from the docs that ng-include loaded and compiled the requested fragment, so I was expecting this to work.

Found a solution in the end, by declaring the following in the directive:
<div ng-include src="view.getView()"></div>
and the following in the directive controller:
$scope.view = {
getView: function() {
return "partials/" + $scope.obj + ".html";
}
};
Works perfectly now!

In comment on the comment of Shane Gadsby: it is not <div ng-include src="'partials/'+{{obj}}+'.html'"></div> but <div ng-include src="'partials/'+obj+'.html'"></div>.
Your comment explains why 'this is what you need to force it from object literals to a string', so everything not in single quotes is handled by the compiler as a scope object.

Related

AngularJS expressions not working in <img-crop>

I am trying to modify the project ngImgCrop (https://github.com/alexk111/ngImgCrop) for allowing crop multiple images in the same page, but I do not know how many images I would need, this is created dynamically. So, I need to associate to the 'image' field of a dynamic value, and at the same time I put this variable in my scope. The problem is that this label is not evaluating the angular code.
<div class="cropArea" id="{{'person'+person.Id}}">
<img-crop image="{{'person'+person.Id}}" result-image="myCroppedImage"></img-crop>
</div>
Even when they have the same code, when the page is loaded the html code shows:
<div class="cropArea" id="person12345">
<img-crop image="{{'person'+person.Id}}" result-image="myCroppedImage"></img-crop>
</div>
In my scope since the beginning the variable $scope.person12345 is created, but It is impossible to make the binding without this part.
What can I do?
Note:
In my init() function I create all the variables:
angular.forEach(persons, function (person, index) {
$scope['person'+person.Id]='';
});
I actually can see the variable $scope.person12345 when the page is loaded. In any case why does the expression worked for the div and not for the img-crop?
Please put your expression as a function which will execute in the Controller. string(appending string) will return by a function like below.
<div class="cropArea" id="{{'person'+person.Id}}">
<img-crop image="getImagePath(person.Id)" result-image="myCroppedImage"></img-crop>
</div>
Controller like below:
$scope.getImagePath = function(id){return 'person'+id+'.png';};
Some how there is no parser available in the directive of image, that's why you need to give parsed expression via a controller.

AngularJS: Script tag not working in ng-include

I have a file index.html with the following code:
<div ng-include="'fragment-1.html'"></div>
The code of fragment-1.html:
<b>Inside Fragment 1</b>
<script type="text/javascript">
alert("Inside Fragment 1");
</script>
When I load index.html into the browser, output is:
Inside Fragment 1
The DOM has the <script> tags but the alert is not shown.
My hypothesis:
Because the DOM loads first along with the Angular modules and then Angular checks and binds the data(in this case, fragment-1.html file content) to the view(index.html), it just adds the elements of fragment-1.html in DOM. To execute the JS inside fragment-1.html, we should create a hack for it. Am I right in this explanation? Or is there something else that I may be missing?
I had to load jQuery before loading Angular. The explanation is in the link specified above. Explanation: script not running in templateurl
To include another partial HTML file in your parent HTML file, one can also use Angular directives, depending on the situation. See this answer for when to use ng-include and when to use directives: https://stackoverflow.com/a/24172025/3132646
You don't need to hack. Angular gives you a neat and simple solution to what you want to achieve with your code.
Controller
.controller('fragmentOneCtrl', function ($scope) {
alert('"Inside Fragment 1"');
})
View
<div ng-repeat="go in ['go', 'gogo']" ng-include="'includeThis'">
</div>
<script type="text/ng-template" id="includeThis">
<div ng-controller="fragmentOneCtrl">
</div>
</script>
You may want to use $sce.trustAsHtml before injecting the resource in html

Evaluating moustache expressions after the page was initialized (dynamic binding)

I have a HTML-Document containing moustache expressions that angular-dart evaluates very well:
</head>
<body ng-cloak>
<ctrlTextElements>
<div id="stage">outside: {{ctrlTextElements.test1('three')}}</div>
</ctrlTextElements>
I want to dynamicaly add some HTML with moustache expression like so:
CtrlTextElements.addTextElement(mousePos.x, mousePos.y);
var div = dom.querySelector('#stage');
HttpRequest.getString("../path/text.html").then((r) {
div.children.add(new Element.html(r, validator: new AllowAllValidator()));
});
The content of the added text.html looks like this:
<div>inside: (not evaluated): {{ctrlTextElements.test1('three')}}</div>
That's the result in the browser:
outside: three
inside: (not evaluated):{{ctrlTextElements.test1('three')}}
How can I reevaluate the moustache expressions inside content that has been applied after the page was loaded?
The problem is that you are mixing jQuery like logic with angular logic here : manipulating the dom 'by hand' is rarely a good solution.
The problem here is that your newly added binding has not been compiled by angularjs = it has not been indexed as a directive that should be watched for and updated when scope changes.
Either you try a more angular way, for example using ng-hide or ng-repeat directive to display your content according to the controllers $scope (or another custom directive), or you try to $compile your newly added directive ( but this is bad ) : https://docs.angularjs.org/api/ng/service/$compile .
Maybe try in your controller :
$scope.$compile( div );
Not sure of the syntax though. Maybe you would need to write
<span ng-bind="..."></span>
instead of
{{ ... }}
to make it work.
#Alexhv is right. Sorry for my previous answer. I assumed it is about Polymer. Was already time for bed.
You can find a code example in my answer to this question: setInnerHtml doesn't evaluate Mustache
The pub package bwu_angular (http://pub.dartlang.org/packages/bwu_angular) contains this code as a Decorator (Directive) named bwu-safe-html

ng-include onload not working anymore in angularjs 1.2.0 rc

I am using angular's ng-include like this :
main html:
<span ng-include="'tpl.html'" ng-controller="TplCtrl" onload="loadMe()"></span>
template tpl.html:
<h2>{{ tplMessage }}</h2>
the controller:
$scope.loadMe = function () {
$scope.tplMessage = 'template';
}
})
this was working fine with angularjs 1.1.5 but not anymore in 1.2.0 rc 3
here is a plunkr :
http://plnkr.co/edit/zYRevS?p=preview
any idea how to make this work with 1.2.0 ?
edit:
i saw this : https://github.com/angular/angular.js/issues/3584#issuecomment-25279350
but can't find the answer to this problem here.
ok i found the answer here : https://github.com/angular/angular.js/issues/3584#issuecomment-25857079
ng-include can't be on the same element as ng-controller. In 1.1.5, it was working
here is a working updated plunker with an html element wrapping the ng-include:
http://plnkr.co/edit/CB8jec?p=preview
It seems to have to do with you mixing 2 things on the same tag - it has both ng-include and ng-controller on it. put your span inside of a new one and move the ng-controller to the outside tag.
They might'of changed the order in which these attributes are processed. In general I think mixing them on the same tag is not a good idea.
Because it's just broken, and there is currently no workaround.
According to the change long:
"previously ngInclude only updated its content, after this change ngInclude will recreate itself every time a new content is included. This ensures that a single rootElement for all the included contents always exists, which makes definition of css styles for animations much easier."
but instead of being improved, it appears to have been broken.
According to the comments here the current implementation is broken.
Other sources will tell you the same.

How can I display HTML in a <div> with Angular 1.2.0 - rc2

I am trying to display some HTML in my web page and using the following:
xx {{ pageHtml }} yy
<div data-ng-bind-html-unsafe="$scope.pageHtml"></div>
The data between xx and yy shows up as raw HTML but what I want is to not show it as raw. I used the code on the second line but nothing shows.
Is there something I am missing? Did something change in 1.2 because I thought this was working before?
Update - I do 100% trust the HTML and don't want to clean it. There will be code inside the HTML that needs to show on the screen.
By default the innerHTML-ed expression result is sanitized using the $sanitize service which would require you to include ngSanitize in your module's dependencies.
<div data-ng-bind-html="pageHtml"></div>
However if you trust the HTML to be safe, you can bypass sanitization using $sce service that you would inject in your controller:
$scope.someSafeContent = $sce.trustAsHtml("<i>Hello</i> <b>World!</b>");
HTML:
<!-- bypasses sanitizaton -->
<div data-ng-bind-html="someSafeContent"></div>
Controller
myApp.filter('unsafe', function($sce) { return $sce.trustAsHtml; });
In View
This will resolve your problem.

Resources