angularjs click event inside the ngBindHtml directive - angularjs

I have an angularjs sample code snippet here where i can bind the html tags using ng-bind-html directive. But how can I include some other tags like angularjs ng-click, id tag etc inside ngBindHtml directive like
Test
My sample code is here:
var app = angular.module("myApp", ['ngSanitize']);
app.controller("myCtrl", function($scope) {
$scope.myText = "<a href='#' ng-click='someFunction()'>Test</a>";
$scope.someFunction = function(){
alert("Link Clicked");
};
});
FYI, the data is loaded dynamically from server side script and i have to use ng-bind-html inside ng-repeat directive and i have to pass respective id's to click events something like ng-click="myFunction(x.id)" as in sample 2.

As suggested #Dr Jones, you need use $compile directive.
Live example on jsfiddle.
angular.module('ExampleApp', [])
.controller('ExampleController', function($scope) {
$scope.myText = "<button ng-click='someFunction(1)'>{{text}}</button>";
$scope.text = "Test";
$scope.someFunction = function(val) {
console.log(val);
};
})
.directive('bindHtmlCompile', function($compile) {
return {
restrict: "A",
scope: {
bindHtmlCompile: "="
},
link: function(scope, elem) {
scope.$watch("bindHtmlCompile", function(newVal) {
elem.html('');
var newElem = angular.element(newVal);
var compileNewElem = $compile(newElem)(scope.$parent);
elem.append(compileNewElem);
});
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController">
<h3>
Write code for test button
</h3>
<textarea cols="100" ng-model="myText"></textarea>
<div bind-html-compile="myText">
</div>
</div>
</div>

Related

Render a directive from a dynamic text

I'm trying to use a custom directive loaded from a dynamic text, 'till now I've created the directive and if I use this directive in the HTML file works, but what I want to do is use this directive in a model (string).
This is a sample
https://jsfiddle.net/4Lg42e9d/2/
<div ng-app="test">
<div class="holder" ng-controller="MainController">
<div class="question">
<label ng-bind-html="saveHtml">{{saveHtml}}</label><br>
<input type="text" ng-model="current.answer">
</div>
<button ng-click="goNextQuestion()">Next</button>
<hr>
<answer></answer>
<br>
<br>
<div>{{config}}</div>
</div>
</div>
js file:
'use strict';
var app = angular.module('test', ['ngSanitize']);
app.controller('MainController', function($scope, $sce){
var index = 0;
$scope.config = [
{
"id": "uniqueIdOne",
"question": "What is your name?",
"answer" : ""
},
{
"id": "uniqueIdTwo",
"question": "Great <answer></answer>, <strong>this is some random text</strong>.",
"answer": ""
}
];
$scope.goNextQuestion = function(){
$scope.current = $scope.config[++index];
$scope.trustHtml();
}
$scope.trustHtml = function(){
$scope.saveHtml = $sce.trustAsHtml( $scope.config[index].question );
}
$scope.current = $scope.config[0];
$scope.trustHtml();
});
app.directive('answer', function() {
return {
template: 'This is rendered by the directive answer.',
};
});
I can load the text with the directive, but do not render the content.
The question is: How can i trigger the directive render?
Thanks in advance!
You should create a directive to compile the text with the directive inside.
Using $compile service so you can trigger the directive render, like:
JS
app.directive('myDirective',[ '$compile', function($compile){
return {
restrict: 'A',
link: function($scope, iEle, attrs){
var compiledTpl;
function destroyData() {
if (compiledTpl) {
compiledTpl.remove();
compiledTpl = null;
}
if ($scope.$newScope) {
$scope.$newScope.$destroy();
$scope.$newScope = null;
}
}
$scope.$watch(attrs.myDirective, function (tpl) {
destroyData();
if (tpl) {
tpl = '<div>' + tpl + '</div>';//make sure tpl is a html template.
$scope.$newScope = $scope.$new();
compiledTpl = $compile(tpl)($scope.$newScope);// compile the directive in string (trigger the directive render).
iEle.append(compiledTpl);
} else {
iEle.html('');
}
});
$scope.$on('$destroy', destroyData);//avoid memory leak.
}
};
}]);
HTML
<div my-directive="config[1].question"></div>
Link demo: https://jsfiddle.net/kw04qrdb/

AngularJS directive in $http json response

I try the same thing as here
I retrieve with Ajax server Data which Json contains the markup with a directive and trying to use $compile to fire up this one but at this point without any luck
here is my controller where I try use $compile
angular.module('blancAppApp')
.controller('SlugCtrl', function ($scope, WpApi, $compile, $filter, ngProgressLite) {
// the Content to be rendered.
$scope.post = [];
//loading animate starts
ngProgressLite.start();
loadRemoteData();
// load remote data from the server.
function loadRemoteData() {
// The WpApiService returns a promise.
WpApi.getContents()
.then(
function( post ) {
applyRemoteData( post );
});
}
// apply the remote data to the local scope.
function applyRemoteData( newContents ) {
var compiled = $compile( newContents )($scope);
console.log(compiled); // this one shows me the object then object.content contains my masonry directive
firebug output: <div class="ng-scope">[object Object]</div>
}
//loading animate ends
ngProgressLite.done();
}).directive('compiled', function($timeout) {
return {
restrict: 'E',
scope: {
compiled: '=compiled'
},
link: function (scope, element, attrs, $timeout) {
element.append(scope.compiled);
}
};
});
the directive which should be called
angular.module('blancAppApp')
.directive('masonry', function(scope, element, attrs, $timeout) {
console.log('asdasd');
var container = element.querySelector('#grid');
var msnry = new Masonry( container, {
// options...
itemSelector: '.masonry-brick',
columnWidth: 200
});
return {
restrict: 'E'
};
});
the generated view
<div ng-repeat ="article in post " id="#main-content">
<div ng-bind-html="article.content | unsafe">
<div ng-controller="ContentCtrl">
{{ article.content }}
</div>
</div>
</div>
Generated Markup with directive call
<div id="grid" masonry="">
<div class="masonry-brick "><img src=""... /></div>
<div class="masonry-brick "><img src=""... /></div>
<div class="masonry-brick "><img src=""... /></div>
</div>
plunker
You use $compile incorrectly. $compile returns "a link function which is used to bind template". So you need to call returned function. Try:
var compiled = $compile($scope.post)($scope);
console.log(compiled);
Resulting element must be then attached somewhere to DOM document for example with directive:
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.js"></script>
</head>
<body ng-app="plunker">
<div data-ng-controller="SlugCtrl">
<div id="compiled_content" data-compiled="compiled">
</div>
</div>
<script>
var app = angular.module('plunker', []);
app.controller('SlugCtrl', function ($scope, $compile) {
$scope.some_var = 'var content';
var template = '<div>{{some_var}}</div>';
$scope.compiled = $compile(template)($scope);
$scope.some_var = 'var content canged';
}).directive('compiled', function() {
return {
restrict: 'A',
scope: {
compiled: '=compiled'
},
link: function (scope, element, attrs) {
element.append(scope.compiled);
}
};
});
</script>
</body>
</html>
I used element.append(scope.compiled); and not just {{scope.compiled}} because compilation result is object and not a string.
Your applyRemoteData function must be like this:
function applyRemoteData( newContents ) {
$scope.compiled = $compile('<div>' + newContents + '</div>')($scope);
}

AngularJS: Using directives within dynamic HTML

I'm attempting to build dynamic HTML strings which include a directive that reacts to changes in a scope variable. If I build the strings statically then my $watch works properly, but if the strings are dynamic then the $watch never fires.
I am sure the answer lies somewhere in use of $compile, and I have studied numerous examples, but I can't seem to make them work for my specific needs.
Is this possible?
My plunkr, which demonstrates referencing sentences with a superscript tag.
index.html
<body ng-controller="MainCtrl">
<h3>Static Example</h3>
<div>Humpty Dumpty sat<ref><sup>1</sup></ref> on a wall.</div>
<div>Humpty Dumpty had a great<ref><sup>2</sup></ref> fall.</div>
<h3>Dynamic Example</h3>
<div ng-repeat="item in dynamic">
<span ng-bind-html="item | to_trusted"></span>
</div>
<br>
<input type="checkbox" ng-click="sup = !sup"> hide/show
</body>
app.js
var app = angular.module('app', [])
.filter('to_trusted', ['$sce', function($sce) {
return function(text) {
return $sce.trustAsHtml(text);
};
}]);
app.controller('MainCtrl', function($scope) {
$scope.sup = true;
$scope.dynamic = ["Humpty Dumpty sat on a wall.<ref><sup>1</sup></ref>",
"Humpty Dumpty had a great fall.<ref><sup>2</sup></ref>"];
});
app.directive('sup', function($compile) {
return {
restrict: 'E',
link: function(scope, element) {
scope.$watch('sup', function() {
element.css({ display: scope.sup ? 'inline' : 'none' });
});
}
}});
You have to change your directive like below.
app.directive('compile', ['$compile', function ($compile) {
return function (scope, element, attrs) {
scope.$watch(
function (scope) {
return scope.$eval(attrs.compile);
},
function (value) {
element.html(value);
$compile(element.contents())(scope);
}
);
};
}]);
then use it in html like this.
<h3>Dynamic Example</h3>
<div ng-repeat="item in dynamic">
<span compile="item"></span>
</div>
Demo code

AngularJS: include not working from a custom directive

I have a custom directive and I would like to use it to include an html content to the document after clicking on it.
Plunker: http://plnkr.co/edit/u2KUKU3WgVf637PGA9A1?p=preview
JS:
angular.module("app", [])
.controller("MyController", function ($scope) {
})
.directive('addFooter', ['$compile', '$rootScope', function($compile, $rootScope){
return {
restrict: 'E',
template: '<button>add footer</button>',
controller: 'MyController',
link: function( scope, element, attrs, controller) {
element.bind( "click", function() {
scope.footer = "'footer.html'";
})}
};
}])
HTML:
<body ng-app="app">
<script type="text/ng-template" id="footer.html">
FOOTER
</script>
<div ng-controller="MyController">
<add-footer></add-footer>
<div ng-include="footer"></div>
</div>
</body>
Not sure why it is not working, as it worked fine before it was moved into the directive. Outside the directive, I was also referencing to $scope.footer with some link. I tried using $rootScope, but also no effect. Any tips please?
First. Remove unnecessary quote symbols:
element.bind( "click", function() {
scope.footer = "footer.html"; // not "'footer.html'"
});
Second. You should notify angularjs that you have asynchronously updated scope values:
element.bind("click", function() {
scope.$apply(function() {
scope.footer = "footer.html";
});
});
Or like that
element.bind("click", function() {
scope.footer = "footer.html";
scope.$apply();
});

AngularJS. Multiple select JQuery plugin

What is proper way to implement this bootstrap select plugin (http://silviomoreto.github.io/bootstrap-select/) to angular. I have put it in the directive:
App.directive('selectmultiple', [function(){
return function(scope, element, attributes){
element = $(element[0]);
element.selectpicker({
})
}
})
But it's not working. If I write in Chrome console $('.selectpicker').selectpicker({}) - proper combobox appear (opened), but a can't close it.
Thanks
I created a working example in jsfiddle. The way I found to use bootstrap-select plugin with angular was:
HTML:
<div ng-app="myApp">
<div ng-controller="MyCntrl">
<select ng-model='color' multiple ng-multiple="true" ng-options='c.name for c in colors' select-multiple></select>
</div>
</div>
Controller:
angular.module('myApp.controllers', [])
.controller('MyCntrl', ['$scope', function($scope) {
$scope.colors = [
{name:'black'},
{name:'white'},
{name:'red'},
{name:'blue'},
{name:'yellow'}
];
$scope.color = $scope.colors[2]; // red
}]);
Directive:
angular.module('myApp.directives', [])
.directive('selectMultiple', function() {
return function(scope, element, attributes){
element.selectpicker({});
scope.$watch(function () {
return element[0].length;
}, function () {
element.selectpicker('rebuild');
});
// Watch for any changes from outside the directive and refresh
scope.$watch(attributes.ngModel, function () {
element.selectpicker('refresh');
});
}
});
I hope it helps you ;)

Resources