I've been trying to improve myself on angularjs so i've started a project with angularjs in it. But i got stuck ...
I'm trying to ng-repeat some html elements using controller1.modalItems. Within the html template like below, i also want to dynamically add another template.
<div ng-repeat="li in modalItems">
<div ng-include="test.html"></div>
<div class="head">{{li.title}}</div>
</div>
here is the test.html
<script type="text/ng-template" src="test.html">
<ul >
<li ng-repeat="t in items">
<img src="{{ t.img }}" alt="" title="" />
</li>
</ul>
</script>
how can i pass the controller that it needs to repeated to test.html template.
You can pass the controller using ng-controller directive:
<div ng-include="test.html" ng-controller="theController"></div>
Don't do that
https://docs.angularjs.org/api/ng/directive/ngController
A common mistake is to declare the controller again using ng-controller in the template itself. This will cause the controller to be attached and executed twice.
Related
I'm trying to load a template into an Angular app depending on a parameter. It would be inside a ng-foreach:
<body ng-app="MyApp" ng-controller="ExampleController as example">
<div ng-repeat="item in example.items" class="someClass" ng-switch="item.type">
<!-- load a different template (partial) depending on the value of item.type -->
</div>
</body>
Fiddle: https://jsfiddle.net/rsvmar2n/1/
Can I somehow do that? I was thinking about using ng-switch: https://jsfiddle.net/rsvmar2n/6/
But I'm sure there's a more angular way to do it.
Edit: I would like NOT to do an http request for every partial I would load (and I think ngInclude does that.
Edit2: Ended using ng-include and cached templates. https://jsfiddle.net/rsvmar2n/24/
You can call a function which returns the id of the template in ng-include and use cached templates. The working example shows what you can do.
the function in your controller which handles the template looks like:
$scope.getTemplate = function(item) {
switch(item.type)
{
case "type1":
return 'testtype1.html';
default:
return 'testtype2.html';
}
}
and your html
<script type="text/ng-template" id="testtype1.html">
<p>This is the template 1</p>
</script>
<script type="text/ng-template" id="testtype2.html">
<p>This is the template 2</p>
</script>
<body ng-app="MyApp" ng-controller="ExampleController">
<div ng-repeat="item in items" class="someClass">
<!-- load a different template (partial) depending on the value of item.type -->
<div ng-include="getTemplate(item)"></div>
</div>
</body>
Create directive for that, something like:
app.directive('myDirective', function(){
return {
restrict: 'E',
scope: {item: '=item'},
templateUrl: function(element, attrs){
if (!attrs.type) return 'default.html';
return attrs.type + '.html';
}
}
});
Then you can create different templates like type1.html, type2.html...
And in controller you just do:
<my-directive ng-repeat="item in items" item="item", type="item.type">
Using ng-include lets you dynamically assign the source - so in your parent template you could have
<div ng-include src="templateName"></div>
where templateName is a variable name in your controller
$scope.templateName = 'path/to/my/template.html';
and changing this value within a digest should dynamically update the contents for you
Based on conditions you can load single or multiple templates as shown below.
With ng-switch
ng-if="item.type=='type2'||item.type=='type3'"
LoadMultipleTemplate To load multiple template based on your selections.
LoadSingleTemplate load single template.
Edit
With ng-include, this way you can load dynamic views.
in this example I've not put any condition. but within ng-repeat you can put another ng-repeat and based on inner ng-repeat you can do the stuff. But for inner ng-repeat you will have to make according json object.
loadViews
<div ng-repeat="item in example.items" class="someClass" >
<ng-include src="item.type + '.html'">{{item.type}}</ng-include>
</div>
I am trying to apply the filters on the ng-repeat based on user selection in section options.But unable to do that so far.
Update-It works !!
Here's Plunker
HTML
<div class="container">
<div ng-include="" src="'refiners.html'"></div>
<br />
<br />
<div class="row">
<div class="col-xs-12">
<ul>
<li ng-repeat="item in data.Results | filter:cc">
<div>
<p>{{item.Title}}</p>
<p>{{item.City}}</p>
<p>{{item.PostalCode}}</p>
<span>{{item.MinimumSalePrice | currency}}</span>
<span>{{item.MaximumSalePrice |currency}}</span>
<p>{{item.PropertyType}}</p>
<p>{{item.TenureType}}</p>
</div>
</li>
</ul>
</div>
When you do ng-include you create a new scope so cc is always empty in the parent scope.
This is similar to the issue in this in question. AngularJS - losing scope when using ng-include
You can fix it by adding $scope.cc={} to your controller (creating this element in the parent $scope so the filter has access to it. For this to work you will have to remove the ng-init calls from refiners.html, since these will create a new object in the child scope.
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.
Is it possible to call the controller action in javascript. I tried in the following way but it wont work
$('#members').html({%render(controller('AmvMembersBundle:Pages:EditMembers'))%});
Replace {% %} with {{ }}. Then it should show content.
A better solution in this case is to put the render funciton inside a div, then control its visibility with JS.
<div id="members">
<div class="edit hidden">
{% render(controller('AmvMembersBundle:Pages:EditMembers')) %}
</div>
</div>
<script>
$('#members').find('.edit').removeClass('hidden');
</script>
Although, if you need this to be dynamically called, you should load the controller via AJAX.
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}}">