generate dynamic html on ng click - angularjs

I want to insert dynamic html element which contains ng-bind and directive on ng-click. I want to insert new html elements inside
Html looks like this
<body data-ng-controller="controller">
<div id="toolbox">
<label>Page Width</label>
<input type="text" data-ng-model="pageWidth" />
<input type="button" value="H1" data-ng-click="createH1()" />
</div>
<div id="editor">
<div data-ng-style="{width:pageWidth + 'px'}" data-ng-page>
</div>
</div>
</body>
Controller >
app.controller('controller', ['$scope', function ($scope) {
$scope.createH1 = function () {
document.getElementById("page").innerHTML = document.getElementById("page").innerHTML + ("<div class='h1' data-ng-h1 draggable></div>");
};
}]);
The above controller is inserting html element, but the directives of new html elements are not working.
However I came to know that unless we $compile template/html they'll not work. If I use app.directive( ngPage, ..) to add my dynamic html, it is inserting while app is started. But I want to insert only on button ng-click.
I'm new to angular js, a bit confused please help me out with this.
Thanks in advance.

I will Always prefer to do DOM manipulation from directive. So here code will look like below
HTML
<body ng-controller="MainCtrl as vm">
<button add-html>click me</button>
<div id="page">
This will be replaced by text
</div>
</body>
CODE
app.directive('addHtml', function($compile){
return {
restrict: 'AE',
link: function(scope, element, attrs){
var html = `<div class='h1' data-ng-h1 draggable>Test</div>`,
compiledElement = $compile(html)(scope);
element.on('click', function(event){
var pageElement = angular.element(document.getElementById("page"));
pageElement.empty()
pageElement.append(compiledElement);
})
}
}
});
Plunkr Here

Related

Angularjs directive, call same directive from within itself

I am building generic angularjs directive to support editing of json object. I have json data and also admin data to have details about original data. Following code details which I am using to build my generic directive.
Please refer Plunker for running code.
http://plnkr.co/edit/x2lqHjYq48gwxW7oYyEQ?p=preview
Directive Code:
app.directive("objecteditor", [function () {
return {
restrict: "E",
templateUrl: "ObjectEditor.html",
replace: true,
scope: {
object: '=',
objectAdmin: '='
},
link: function (scope, element, attrs) {
//Method to initialize
scope.init = function () {
};
//Call init() to initialze the loading.
scope.init();
}
};
}]);
Directive Template:
<div>
<h4 data-ng-bind-template="{{objectAdmin.displayName}}"></h4>
<div data-ng-repeat="column in objectAdmin.objectDefinition">
<div data-ng-switch="column.type">
<div data-ng-switch-when="string">
<label class="label-plain" data-ng-bind-template="{{column.displayName}}"></label>
<input type="text" data-ng-model="object[objectAdmin.name][column.name]" placeholder="{{displayName}}" title="{{displayName}}" name="textBox{{name}}" required />
</div>
<!--Call same object for child type as object. But how??? If i call <object> directive here then goes into infinite cycle -->
<div data-ng-switch-when="object">
</div>
</div>
</div>
</div>
Controller Code:
var app = angular.module("myApp", []);
app.controller('ApplicationController', ['$scope',
function($scope) {
//Method to initialize
$scope.init = function() {
//Set json data strucutre for editing
$scope.objectAdmin ={"name":"bankinfo","displayName":"Bank Info","type":"object","objectDefinition":[{"name":"name","displayName":"Bank Name","type":"string"},{"name":"mainPhone","displayName":"Main Phone","type":"string"},{"name":"contact","displayName":"Contact","type":"object","objectDefinition":[{"name":"name","displayName":"Name","type":"string"},{"name":"title","displayName":"Title","type":"string"}]}]};
$scope.object={"bankinfo":{"name":"Chase Bank - Newburgh","mainPhone":"1 (845) 333-3333","contact":{"name":"Donna Shuler","title":"Commercial Accounts Mgr."}}};
};
//Call init() to initialze the loading.
$scope.init();
}
]);
Index.html
<!doctype html>
<html ng-app='myApp'>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="script.js"></script>
<script src="ObjectEditor.js"></script>
</head>
<body data-ng-controller="ApplicationController">
<h2>How to call same directive within itself?</h2>
<!--Use object editor directive to edit the object details -->
<objecteditor data-object="object" data-object-admin="objectAdmin"></objecteditor>
</body>
</html>
I want to make my directive generic so that same type of object editing can be supported by single directive.
When I tried to call same directive within itself then it fall into infinite loop (which is expected).
How can I achieve this functionality in directive?
Please help.
I was going through the recursive directive and came across following post which was helpful to implement my requirement.
https://www.packtpub.com/books/content/recursive-directives. Following is code to implement this.
Object Editor Directive Template:
<div>
<objecttree data-object="object" data-object-admin="objectAdmin" data-folder-guid="folderGuid" data-hide-header="'true'"></objecttree>
<script type="text/ng-template" id="objectTree">
<div class="clear-left">
<h4 data-ng-if="!hideHeader" data-ng-bind-template="{{objectAdmin.displayName}}"></h4>
<div data-ng-repeat="column in objectAdmin.objectDefinition">
<div data-ng-switch="column.type">
<imageeditor data-ng-switch-when="image" data-image="object[column.name]" data-folder-guid="folderGuid" data-column="column"></imageeditor>
<formcheckbox data-ng-switch-when="boolean" data-input-value="object[column.name]" data-editable="column.editable" data-name="column.name" data-display-name="column.displayName" data-formName="'resourceAddEditFormName'"></formcheckbox>
<addresseditor data-ng-switch-when="address" data-address="object[column.name]" data-column="column" data-collection-admin="objectAdmin"></addresseditor>
<formtextbox data-ng-switch-when="string" data-ng-if="!column.isDropdown" data-input-value="object[column.name]" data-editable="column.editable" data-name="column.name" data-display-name="column.displayName" data-formName="'resourceAddEditFormName'"></formtextbox>
<dropdownbox data-ng-switch-when="string" data-ng-if="column.isDropdown" class="admin-textbox" data-selected-id-list="object[column.name]" data-dropdown="column" data-multiple="column.dropdownTypeMultiple"></dropdownbox>
<div data-ng-switch-when="object">
<hr/>
<objecttree data-object="object[column.name]" data-object-admin="column" data-folder-guid="folderGuid" data-hide-header="'true'"></objecttree>
</div>
<div data-ng-switch-when="array">
<hr/>
<arrayobjecttree data-objects="object[column.name]" data-objects-admin="column" data-folder-guid="folderGuid" data-hide-header="'true'"></arrayobjecttree>
</div>
</div>
</div>
</div>
</script>
</div>
Object Tree:
app.directive("objecttree", ['$compile', '$templateCache', function ($compile, $templateCache) {
return {
restrict: "E",
scope: {
object: '=',
objectAdmin: '=',
folderGuid: '=',
hideHeader: '='
},
link: function (scope, element, attrs) {
element.replaceWith(
$compile(
$templateCache.get('objectTree')
)(scope)
);
}
};
}]);
This is Shankar. You can use the below solution for recursive directive.
Please confirm me whether this resolves your issue.If not, you can let me know.
As I'm not able to paste my entire code here, you can find the solution in my Github repository:(i.e. gmssankar/myRepository/Recursive Directive)
https://github.com/gmssankar/myRepository/blob/master/Recursive%20Directive
The code can be found in the following link too in plunker:
plnkr.co/edit/WrZekRS5AzfFJhQ2d3XK?p=preview
I'm not able to attach the complete code here as it restricts the number of lines. The logic is: Inside Directive template display bank name, main phone,contact name and contact title from the passed object. Then check if the passed object, has object definition (i.e child nodes). If yes, then extract each child using ng-repeat , and pass to same directive. Issue gets resolved here. From Github or plnkr , you can access the complete code.

How to create an element on button click?

I want to create dynamically an element when I click on a button. Do I have to use ng-click or a directive for that?
Here is a JSFIDDLE of what I'm trying to achieve using jQuery :
HTML:
<button id="myButton">Click Me</button>
<div id="container"></div>
JS:
$("#myButton").on("click", function() {
$("#container").append('<div class="box"></div>');
});
Also, here is a base JSFIDDLE, of what I have so far, to work on if you want for an angularjs solution.
Warn:
Please avoid a solution with a controller using ng-repeat. The code above is a simplified example. The created elements won't be as a list, because I'll attach a drag directive to them.
Do I have to use ng-click or a directive for that?
To create new element I would use $compile. Any DOM manipulations I strongly recommend to do in directives only. You can trigger appending process through ng-click directive or to use bind like:
element.bind("click", function(e){
// do stuff here
});
Something like that:
demo.directive("boxCreator", function($compile){
return{
restrict: 'A',
link: function(scope , element){
element.bind("click", function(e){
var childNode = $compile('<button ng-click="doStuff()" >new button</button>')(scope)
element.parent().append(childNode);
});
scope.doStuff = function(){
// do stuff
}
}
}
});
Demo Fiddle
http://jsbin.com/cuciyu/2/edit
JS
var app = angular.module('app', []);
app.directive("addDiv", function($compile){
return{
restrict: 'AE',
link: function(scope , element,attr){
element.bind("click", function(e){
var container = angular.element(document.querySelector("#container"));
var childNode = $compile('<div class="box">BOX DIV</div>')(container);
container.append(childNode);
});
}
};
});
app.controller('firstCtrl', function($scope){
});
HTML:
<body ng-app="app">
<div ng-controller="firstCtrl">
<button add-div>Click Me</button>
<div id="container"></div>
</div>
</body>

how to set visibility to a class with angular.js

using angular.js is there a way to set the visibility of all the elements in the page with a specific class using a single model variable?
the angular equivalent of
$(".myClass").hide();
thanks,
Luca
In html code you can use directive
<div ng-show="shouldShow"></div>
and in controller
$scope.shouldShow = (true or flase)
Try ngClass
Take a look at this.
Here depends upon the Boolean value of $scope.data the content will be shown or hidden.
i.e if $scope.data = true content will be hidden, and if false content will be shown
Working Demo
Html
<div ng-app='myApp' ng-controller="ArrayController">
<div ng-class="{show: data, hide:data}">Content</div>
</div>
Script
var app = angular.module('myApp', []);
app.controller('ArrayController', function ($scope) {
$scope.data = true;// for Hiding
});
CSS
.hide{
display:none;
}
I would say to add a directive like this.
directive('className', function () {
return {
restrict: 'C',
link: function (scope, elem, attrs) {
elem.hide();
}
}
});
In MarkUp
<div class="className">Content</div>
Here is an Plunker, made for you.
I think this can be useful to you.Have a look at this jsfiddle
Html
<div ng-app=''>
<div ng-class="selectCss">Content</div>
<input type="button" ng-model="selectCss" value="show" ng-click="selectCss='show'">
<input type="button" ng-model="selectCss" value="hide" ng-click="selectCss='hide'"/>
</div>
Css
.hide{
display:none;
}

ng-include not working with script type="text/ng-template"

Here is my Plunker:
http://plnkr.co/edit/oIei6gAU1Bxpo8VUIswt
When the button is clicked, the following should be inserted before the "Hello World!" span:
<script type="text/ng-template" id="tempTest">
<div>
<span>Properly Inserted</span>
</div>
</script>
minus the script tags, of course.
I achieve this by dynamically inserting the following div:
<div ng-include="tempTest"></div>
And then compiling it. However, if you look at the log, the only thing that is left after the compilation is this:
<!-- ngInclude: tempTest -->
What is going on here? Why isn't my insert properly compiling? the logic is as follows:
$scope.insert = function(){
// Create elements //
var container = angular.element('<div id="compiled-container"></div>');
var element = angular.element('<div ng-include="tempTest"></div>');
//Insert parent Container
$('#greeting').before(container);
// insert the element
$animate.enter(element, container);
// test insertion
console.log("Before Compile: " +container.html() )
$compile(element);
//look again after compile
console.log("After Compile: " +container.html() )
};
The quick answer might have been:
<div ng-include="'tempTest'"></div>
Probably you just forgot the single quotes to reference the template.
The long answer:
It is not advised to access the DOM inside a controller - you will get in trouble as the code will be flooded with $scope.$apply() calls. Think about implementing this feature with a directive. I tried to create a starting point from your code here
http://plnkr.co/UWUCqWuB9d1dn6Zwy3J3
var app = angular.module('plunker', ['ngAnimate']);
app.directive('greeting', function($compile){
return {
restrict: 'E',
scope: {
name: '='
},
template: '<div>'+
' <span>Hello {{name}}!</span>'+
' <button ng-click="insert()">test</button>'+
'</div>',
link: function(scope, element, attrs) {
scope.insert = function() {
var container = angular.element('<div ng-include="\'tempTest.html\'"></div>');
element.before($compile(container)(scope));
}
}
}
})
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
});
<greeting name="name"></greeting>
The template elements are inserted before the Hello World! textnode everytime the button is clicked.
Side note You dont even need the scope{ name: '='} as the directive will inherit its surrounding scope, but its the cleaner way to pass (actually bind) controller variables to a directive explicitly.
<div ng-include src="tempTest"></div>
This should work
^^^ note that this will NOT even begin to work unless single quotes are added (as #JHixson has already pointed out), like so:
<div ng-include src="'tempTest'"></div>
Simply your script :
<script type="text/ng-template" id="tempTest">
<div>
<span>Properly Inserted</span>
</div>
</script>
Must be inside the MainCtrl controller selector like this :
<div ng-app="plunker" ng-controller="MainCtrl">
<script type="text/ng-template" id="tempTest">
<div>
<span>Properly Inserted</span>
</div>
</script>
</div>

ng-click attribute on angularjs directive

I think it should be easy to use the well known angular attributes on a directive out of the box.
For example if the name of my directive is myDirective I would like to use it this way:
<div ng-controller="myController">
<my-directive ng-click="doSomething()"><my-directive>
</div>
instead of needing to define a custom click attribute (onClick) as in the example below
<div ng-controller="myController">
<my-directive on-click="doSomething()"><my-directive>
</div>
It seems that ng-click can work, but then you need to specify ng-controller on the directive tag too which I don't want. I want to define the controller on a surrounding div
Is it possible to use ng-click on a directive together with a controller defined on a parent html element?
Here is updated code. Maybe is this what you were looking for.
Html:
<div data-ng-app="myApp">
<div data-ng-controller="MyController">
<my-directive data-ng-click="myFirstFunction('Hallo')"></my-directive>
<my-directive data-ng-click="mySecondFunction('Hi')"></my-directive>
</div>
</div>
Angular:
var app = angular.module('myApp', []);
app.directive('myDirective', function(){
return {
restrict: 'EA',
replace: true,
scope: {
eventHandler: '&ngClick'
},
template: '<div id="holder"><button data-ng-click="eventHandler()">Call own function</button></div>'
};
});
app.controller('MyController', ['$scope', function($scope) {
$scope.myFirstFunction = function(msg) {
alert(msg + '!!! first function call!');
};
$scope.mySecondFunction = function(msg) {
alert(msg + '!!! second function call!');
};
}]);
Edit
Check solution that I made in jsFiddler is that what you were looking for?
http://jsfiddle.net/migontech/3QRDt/1/

Resources