I'm new to Angular and am trying to understand how to dynamically create new elements. I have an element directive called "pane" that replaces the pane tag with a template.
<pane ng-controller="AreaCtrl"></pane>
Template for pane (condensed):
<div>
<section></section>
<div class="subs"></div>
</div>
When I click on an item inside the section tag, I want to append another "pane" inside the div with class="subs" if the "pane" for the item clicked doesn't already exist. I can't get the appended pane tag to invoke the directive and be replaced by the template. Any point in the right direction would be great for an Angular newbie.
Here is a simple jsfiddle: http://jsfiddle.net/n9vXz/1/
You probably want an array in your model, with a ng-repeat directive:
<div>
Add Item
<section></section>
<div class="subs">
<pane ng-repeat="item in list"></pane>
</div>
</div>
JS:
app.controller("AreaCtrl", function($scope){
$scope.items = [{ name: 'item1' }];
$scope.addItem = function(){
$scope.items.push({ name: 'newItem' });
};
});
I'm not sure how you're appending it to the body, but for showing you how to do it I'll assume it's just an element you have.
var newPaneElement = .....
someOtherElement.append(newPaneElement);
In order for your directive to be processed now, you'll have to tell it to $compile
You can do this by running the following directly after appending it to someOtherElement:
$compile(newPaneElement)($scope OR scope);
I put $scope or scope because I'm not sure if where you're appending it is in a controller, or within a directive.
If you can paste a jsFiddle that would be helpful.
There's no need to do compile, I think you should watch some of the tutorial videos on how to use angular. Looking at the jsfiddle you have, you don't need jquery. Also you have a directive wiring up on the pane element, but then within that directive you have another pane element so it was doing a recursive loop and crashing. I've fixed the fiddle up to do what you need:
JsFiddle http://jsfiddle.net/BcvPz/1/
Use an ng-repeat and then you can just have pane elements repeat wherever
JsFiddle http://jsfiddle.net/BcvPz/2/
Related
I have a problem I have created a directive which is doing ng-repeat on an array of objects
---Showing the value on gui------
Now I want that if I click on any div of this repeat that particular div's background color should change
I have tried something like this
link:function(scope,element,attributes){
$(element).on('click',function(e){
$(element).addClass('A');
$(element).removeClass('B');
})
}
You can use the ng-class directive to apply classes on specific occurences, in your case in combination with the ng-click:
<div ng-repeat="item in items"
ng-class="{A: item.clicked, B: !item.clicked}"
ng-click="item.clicked = !item.clicked">
<!-- .. content -->
</div>
See this jsfiddle for example
You can try something like this, but this will need more workaround.
<div ng-click=“changeBackground($event)”></div>
// In Controller
$scope.changeBackground = function(event){
event.target.style.background = “#000”;
}
It would be better if you can submit your code.
the ng-repeat outputs nothing. in the link function, i can see $scope.clients is an array. if i remove the isolate scope, and use the parent scope, the ng-repeat works.
html with directive "clients".
<div container
ng-cloak
ng-app="summaryReportApp"
ng-controller="summaryReportController as summaryReport">
<fieldset clients="summaryReport.clients">
<legend>Clients</legend>
<div align="left">
<div ng-repeat="client in clients track by $index">
{{client}}
</div>
</div>
</fieldset>
</div>
directive
var clients = function(){
var definition = {
restrict: "A",
scope: {
clients:"=clients"
},
link: function($scope,$element,attributes){
}
}
return definition;
}
This is a common question I seem to answer frequently. Directives can have other HTML Elements nested in them, in the same way that an <input> can be nested inside a <div>. However, the Elements nested inside the Directive are not part of the directive, and are not scoped to the directive, they are scoped to the HTML they are in. The only items that have access to the Isolated Scope are the compile, link, controller, and template items in the directive definition. If you moved your inner html from inside the fieldset into a template, it would function as expected.
You can also reference http://angular-tips.com/blog/2014/03/transclusion-and-scopes/ for more examples and ways to test this.
i tried appending my template to html div tag as shown below my app.js:-
myApp.directive("panel",function(){
return{
restrict:"E",
transclude:true,
template:'<div class=panel ng-transclude >hiii i am panel</div>'
}
});
in my html page i tried to append it to the existing html div tag as shown below:-
<panel>
<div class="button">click me </div>
</panel>
but the text in- template:'<div class=panel ng-transclude >hiii i am panel</div>' which is -hiii i am panel is getting hide from this button -<div class="button">click me </div>, iam not able to see the content inside <div class="panel>....</div> of the template.
I believe you misunderstood. Transclude. Transclude means, "replace everything inside the tag that has ng-transclude on it." It is sort of like saying:
var content = $("panel").html();
$([ng-transclude]).html(content);
If you want to have both of them, then you need to include it separately. Try changing your template to:
<div class="panel"><span>hiii i am panel<span><span ng-transclude></span></div>
Which would show you both.
Here is a fiddle that does it http://jsfiddle.net/17nb3kg1/
How do I go about create an element in my controller? e.g. on a click event?
example controller:
function AddCtrl($scope){
$scope.add = function(){
// do stuff to create a new element?
}
}
example view:
<div ng-controller="AddCtrl">
<button ng-click="add()">Add</button>
// create <input type="text" ng-model="form.anotherField">
</div>
Any suggestions much appreciated.
AngularJS is intended to follow MVC - so the controller creating an element in the view doesn't agree with the MVC behavior. The controller should not know about the view.
It sounds as if you want to have a control appear based on some conditional logic. One approach would be to bind to the visibility of the element.
In Angular, your controllers should not be manipulating the DOM directly. Instead, you should describe the elements you need in your templates, and then control their display with directives, like ng-switch, ng-hide / ng-show, or ng-if, based on your model, ie, your data.
For example in your controller you might do something like:
$scope.showForm = false;
And then in your partial:
<div id="myForm" ng-show="showForm">
<!-- Form goes here -->
</div>
By switching $scope.showForm between true and false, you will see your myForm div appear and disappear.
This is a classical mistake coming from jQuery moving to Angular or any other MVC library. The way you should think is to let the view react to changes in the scope.
$scope.items = []
$scope.add = function(){
$scope.items.push({});
}
In the view:
<input type="text" ng-repeat="item in items" ng-model="item.property">
If you want to display an element based on some condition or after the click, use ng-switch: http://docs.angularjs.org/api/ng/directive/ngSwitch
If you want to add multiple elements, create a repeated list of items and add an item to your view-model on clicking the button:
$scope.yourlistofitems = [];
$scope.add = function() {
$scope.yourlistofitems.push("newitemid");
}
And in the HTML:
<input type="text" ng-repeat="item in yourlistofitems" ng-model="item.property">
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>