How to add ng-click handler dynamically - angularjs

I tried to add ng-click on a button generated before (dynamic), but didn't work well. Also I tried already all solutions found on this forum and no one work well.
My html code:
<body class="max_height" ng-app="myApp">
<div class="container max_height" ng-controller="myCtrl">
<div id="play" tabindex="0" ng-init="init()" ng-keydown="keyDown($event)">
{{ content }}
</div>
</div>
<script src="js/angular.min.js"></script>
<script src="js/script.js"></script>
</body>
My AngularJS code:
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope, $compile) {
$scope.init = function() {
var el = '<button class="btn" id="start" data-ng-click="startAnimation()">Start</buttom>';
var element = angular.element(document.querySelector('#play'));
var generated = element.html(el);
$compile(generated)($scope);
}
$scope.startAnimation = function(){
console.log("click");
}
});
My error is "RangeError: Maximum call stack size exceeded" and this is generated by $compile(generated)($scope); . Another problem, derived from the first, is that if I make one click on button then the function startAnimation will me executed hundreds of times.
Please give me a solution. Where is the mistake.

Issue is with this line of code:
$compile(generated)($scope);
Instead it should be:
$compile(generated.contents())($scope);

You can assign the function to a scope variable and depending on your business logic assign appropriate functions to your ng-click. In the below example $scope.addGeoFence() is added to the ng-click of "Add GeoFence" list-item
$scope.layout = [
{name: 'Home', icon: 'home'},
{name: 'Add Geofence',
icon: 'add_location',
click: $scope.addGeoFence}
];
$scope.addGeoFence = function() {
console.log("calling addGeoFence()");
}
<md-list>
<md-list-item ng-repeat="snav in layout">
<md-button class="md-raised" ng-click="(snav.click)()" flex>
<md-icon md-font-library="material-icons">{{snav.icon}}
</md-icon>
<span>{{snav.name}}</span>
</md-button>
</md-list-item>
</md-list>

Related

Trying to use controllers in AngularJS

I have implemented auto-complete feature, now I am trying to integrate into my main application. This is the controller function which I designed.
(function() {
'use strict';
angular
.module('MyApp')
.controller('DemoCtrl', DemoCtrl);
function DemoCtrl($http) {
this.querySearch = function (query) {
return $http.get('http://127.0.0.1:8888/autocomplete/' + escape(query)).then(function(result) {
return result.data;
});
}
}
})();
This is my HTML for the first scenario:
<div class="autocompletedemoFloatingLabel" ng-controller="DemoCtrl as ctrl" ng-app="MyApp" layout="column" ng-cloak="">
<md-content class="md-padding">
<form name="searchForm" ng-submit="$event.preventDefault()">
<div layout-gt-sm="row">
<md-input-container flex="">
</md-input-container>
<md-autocomplete md-floating-label=""
flex=""
md-item-text="item.Symbol"
md-items="item in ctrl.querySearch(ctrl.searchText)"
md-search-text="ctrl.searchText"
md-selected-item="ctrl.selectedItem"
md-no-cache="ctrl.noCache"
md-input-name="autocompleteField"
required="">
<input>
<md-item-template>
<span md-highlight-text="ctrl.searchText">{{item.Symbol+" - "+item.Name+" ("+item.Exchange+")"}}</span>
</md-item-template>
<div ng-messages="searchForm.autocompleteField.$error" ng-if="searchForm.autocompleteField.$touched">
<div ng-message="required">You <b>must</b> have a favorite movie.</div>
<div ng-message="minlength">Your entry is not long enough.</div>
<div ng-message="maxlength">Your entry is too long.</div>
</div>
</md-autocomplete>
</input>
</div>
</form>
</md-content>
</div>
Now the application currently contains controller in this format:
var app = angular.module("assign8", ["ngAnimate"]);
app.controller("MyCtrl", function ($scope) {
$scope.myValue=false;
$scope.myValue_sec = false;
});
I am very new to angular, I am unable to map the first format to the second one. Kindly let me know how can I map first to second. TIA.
I'm not sure where the confusion lies. The two scenarios are very similar.
app.controller("MyCtrl", function ($scope) {
this.querySearch = function (query) { ... }
});
There are two manners to make the binding in AngularJS.
The controller as that is what is done in the first format, you can see DemoCtrl as ctrl in html the ctrl variable represent your controller, in your controller, you see this, every attribut of this can be accessed via ctrl in html. for example: ctrl.myAttribut.
The second manner is the use of $scope service. that is what is done in the second format. every attribut of $scope can be accessed in html as long as the corresponding controller is called. For example: if in your controller you have $scope.myAttribut, in your html you can access like this {{myAttribut}}.
This worked:
<script>
var app = angular.module("MyApp");
app.controller("DemoCtrl", function ($http) {
this.querySearch = function (query)
{
return $http.get('http://127.0.0.1:8888/autocomplete/' + escape(query)).then(function(result) {
return result.data;
});
}
});
</script>

How to replace text on field after click Angular?

I have HTML code with inline element:
<span class="title" ng-click="update()">Rock</span>
How to replace this element on input element after click for edit?
And then after push enter on input return back span element?
I tried with directives ng-hide(), ng-show(). But I wonder
You can use either
<span class="title" ng-hide="isEdited" ng-click="update()">Rock</span>
or
<span class="title" ng-show="!isEdited" ng-click="update()">Rock</span>
or even
<span class="title" ng-if="!isEdited" ng-click="update()">Rock</span>
In any case you will want to reference something that can be truthy. For example in your controller you would have something like this in your function
/*the init function just makes sure that everything is setup
and nothing caries over from any local storage or anything
else you may be using*/
init();
init function(){
$scope.isEdited = false;
}
$scope.update = function(){
$scope.isEdited = true;
}
What you need to do is set a variable that contains the state;
<html>
<body ng-app="app">
<div ng-controller="mainController as $ctrl">
<span ng-if="!$ctrl.isInEditMode" class="title" ng-click="$ctrl.update()" ng-bind="$ctrl.spanText"></span>
<div ng-if="$ctrl.isInEditMode">
<input type="text" placeholder="Value for rock" ng-model="$ctrl.spanText" />
<button ng-click="$ctrl.update()">Done</button>
</div>
</body>
</html>
angular.module('app', [])
.controller('mainController', function($scope) {
this.isInEditMode = false;
this.spanText = 'Rock';
this.update = (function() {
this.isInEditMode = !this.isInEditMode;
}).bind(this);
});
I have prepared a Codepen that shows an possible solution: http://codepen.io/stefferd/pen/QdQrrv

Display HTML in AngularJS

I have a angular coding what need insert html tags, I found out I can use ngSanitize :https://docs.angularjs.org/api/ngSanitize , but I don't whant load another library in that project.
I tried this: AngularJS : Render HTML in $scope variable in view
but I could not make work.
It's any way to do this without load another angular library?
html:
<div ng-controller="MyCtrl">
<ul class="procedures">
<li ng-repeat="procedure in procedures">
<h4>{{procedure.icon}}</h4>
<div class="procedure-details" ng-show="show">
<p>text here: {{procedure.text}}</p>
<p>your number is: {{procedure.number}}</p>
<p>price you will pay: {{procedure.price}}</p>
</div>
</li>
</ul>
</div>
js:
var myApp = angular.module('myApp', []);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.procedures = [{
icon: '<i class="fa fa-american-sign-language-interpreting" aria-hidden="true"></i>',
text: 'test text',
number: 1,
price: 10000
}];
}
jsfiddle:
http://jsfiddle.net/wD7gR/247/
Starting from version 1.2.0, angular contains $sce service, that can be used to mark html as "safe"
UPDATED JSFIDDLE
angular
.module('myApp',[])
.controller('MyCtrl', function($scope, $sce) {
$scope.procedures = [
{
icon: $sce.trustAsHtml('<i class="fa fa-american-sign-language-interpreting" aria-hidden="true">i am icon</i>'),
text: 'test text',
number: 1,
price: 10000
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<ul class="procedures">
<li ng-repeat="procedure in procedures">
<h4></h4>
<div class="procedure-details" ng-show="show">
<p>text here: {{procedure.text}}</p>
<p>your number is: {{procedure.number}}</p>
<p>price you will pay: {{procedure.price}}</p>
</div>
</li>
</ul>
</div>
</div>
Instead of using ngSanitize you can use $sce az filter like this:
Put this code in app.js :
app.filter('sce', ['$sce', function ($sce) {
return $sce.trustAsHtml;
}]);
Then use in Html like this:
<h4></h4>
I can tell u that u can do like below It should be as following
$scope.html = "<i class='fa fa-american-sign-language-interpreting' aria-hidden='true'></i>";
and
<div ng-bind-html-unsafe="html"></div>
You can do the same for for icon, text or whatever u like... I'm not sure how to do that right now cuz I'm typing this from mobile fone, i hope u will get the idea, if not plz leave comment and i'll write a full function once i get my hands on machine.
You can use angular-sanitize to insert HTML in a view.
Example is given in plnkr
app.filter("trust", ['$sce', function($sce) {return function(htmlCode){
return $sce.trustAsHtml(htmlCode); }}]);

how to add custom md-chips in addition to existing md-chips?

I have designed elements using angular material design . i have used md-chips for rendering skills data as bellow
<md-chips ng-model="user.skills"
readonly="readonly"
placeholder="Enter another skill"
delete-button-label="Remove Skill"
delete-hint="Press delete to remove skill"
secondary-placeholder="Enter a Skill">
<md-chip-template>{{$chip.skill_title}}</md-chip-template>
</md-chips>
In that i have used the user_skills variable to load existing skills.it's loading as i have expected. i need to give the option to add new chips from this . but here when i write skill and enter it'l become empty chip like bellow image.
how to solve it??advanced thanks..
You need to write a function to set 'skill_title'
VIEW
<div ng-controller="BasicDemoCtrl as ctrl" layout="column" ng-cloak="" ng-app="MyApp">
<md-content class="md-padding" layout="column">
<md-chips ng-model="ctrl.skills" readonly="ctrl.readonly" md-transform-chip="ctrl.newSkill($chip)">
<md-chip-template>
<span>
<strong>{{$chip.skill_title}}</strong>
</span>
</md-chip-template>
</md-chips>
</md-content>
</div>
Controller
(function () {
'use strict';
angular
.module('MyApp')
.controller('BasicDemoCtrl', DemoCtrl);
function DemoCtrl ($timeout, $q) {
var self = this;
self.skills = [
{
'skill_title' : 'Angular'
},
{
'skill_title' : 'Material'
},
{
'skill_title' : 'C#'
}
];
self.newSkill = function(chip) {
return {
skill_title: chip
};
};
}
})();
Take a look at this working example.
http://codepen.io/mattspaulding/pen/xZGQyE

In AngularJS, how do I generate a piece of content from template and insert it in the DOM when a link is clicked

I have a number of links on the page, dynamically generated like so:
<a href="#" class="more-info-item" ng-click="showStats(item, $event)">
More information
</a>
I also have a simple custom template that should show an item's name:
<script type="text/ng-template" id="iteminfo.html">
<div class="item-name">
{{item.name}}
</div>
</script>
What I would like to do is: when the link is clicked, to dynamically compile the template, and insert it in the DOM right after the link. I tried using $compile within showStats method to compile the template, but I got an error that $compile wasn't found. How would I go about doing this (and also provide item as part of the scope for the newly generated template)?
Here is a solution using a custom directive which injects the item dynamically using ng-if:
View Solution with Plunker
html:
<script type="text/ng-template" id="iteminfo.html">
<div class="item-name" ng-if="item.visible">
{{item.name}}
</div>
</script>
<div ng-repeat="item in items" >
<a href="#" class="more-info-item" more-info="item" ng-click="item.visible =!item.visible">
More information
</a>
</div>
script:
angular.module('app', [])
.controller('ctrl', function($scope) {
$scope.items = [{name:'apples', visible:false},{name:'pears', visible:false},{name:'oranges', visible:false}];
})
.directive('moreInfo', function($compile,$templateCache) {
return {
restrict: 'A',
scope: '=',
link: function(scope, element, attr) {
var itemInfo = angular.element($templateCache.get('iteminfo.html'));
var lfn = $compile(itemInfo);
element.parent().append(itemInfo);
lfn(scope);
}
};
});
You can use the built-in ngInclude directive in AngularJS
Try this out
Working Demo
html
<div ng-controller="Ctrl">
<a href="#" class="more-info-item" ng-click="showStats(item, $event)">
More information
</a>
<ng-include src="template"></ng-include>
<!-- iteminfo.html -->
<script type="text/ng-template" id="iteminfo.html">
<div class="item-name">
{{item.name}}
</div>
</script>
</div>
script
function Ctrl($scope) {
$scope.flag = false;
$scope.item = {
name: 'Manu'
};
$scope.showStats = function (item, event) {
$scope.item = item;
$scope.template = "iteminfo.html";
}
}

Resources