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/
Related
PLUNKER:
https://plnkr.co/edit/IQpGhinzsHUUqmwbHFmQ?p=preview
I am trying to create a form that reads from some JSON and creates the relevant view. Each set of questions are in their own step. I am having trouble getting access to each input to validate it using AngularJS.
How do I get access to the answers model that is created in the forEach loop?
HTML:
<form ng-app="MyApp" novalidate >
<section class="question step " ng-controller="StepController">
<div class="step-contents">
{{title}}
<step-contents content="content" ></step-contents>
</div>
<button >Prev</button>
<button ng-click="nextStep(content)">Next</button>
</section>
</form>
My AngularJS:
var app = angular.module('MyApp', []);
app.controller('StepController', function($scope) {
$scope.index = 0;
$scope.nextStep = function() {
console.log($scope.answers); // This should be the input data for _THIS_ step only
}
$scope.showStep = function() {
//FOREACH HAPPENS HERE
// Loops over some JSON to generate the following HTML:
$scope.title = "Step 1 title";
var html = '<input type="number" ng-model="answers.amount" />';
html += '<input type="text" ng-model="answers.name" />';
$scope.content = html;
//FOREACH ENDS HERE
}
$scope.showStep();
});
app.directive('stepContents', function ($compile) {
var linker = function(scope, element, attrs){
element.html(scope.content);
$compile(element.contents())(scope);
};
return {
restrict: 'E',
link: linker,
scope: {
content: '=',
},
};
});
Give a name to your form, and then you can access the form elements with $scope.formName.inputName, which will reference the ngModelController of the input. Check out Angular's documentation for ngFormController and ngModelController for more details.
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>
I am building a angular directive.
I am binding a property to isolated scope in directive like
scope : {
contentModel : '='
}
'use strict';
/**
* Tc markdown directive
*/
var myapp = angular.module('myapp',[]);
myapp.directive('tcMarkdown',[function() {
var directive = {};
directive.restrict = 'E';
directive.template = '<div><div class="row"><!--Content edit pane --><div class="col-md-12"><textarea class="form-control editor" ng-model="someobj.text.data"></textarea></div></div></div>{{contentModel}}';
directive.scope = {
contentModel : '='
};
directive.link = function(scope, element, attrs) {
scope.options = {selected : 0};
scope.$watch(function() {
return scope.options.selected;
}, function(newVal) {
if(newVal===1) {
scope.buttonCaption = {text : 'Edit'};
} else if(newVal === 0) {
scope.buttonCaption = {text : 'Preview'};
}
});
};
return directive;
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myapp">
<data-tc-markdown content-model="content"></data-tc-markdown>
</div>
The two way binding is not working.
As I am typing in textarea the model is not updated.
What am I missing ?
I don't see how you are binding the internal contentModel to your textarea.
Here is an updated working fiddle.
I replaced the someobj.text.data assigned to ng-model with contentModel:
myapp.directive('tcMarkdown',[function() {
var directive = {};
directive.restrict = 'E';
directive.template = '<div><div class="row"><!--Content edit pane --><div class="col-md-12"><textarea class="form-control editor" ng-model="contentModel"></textarea></div></div></div>';
directive.scope = {
contentModel : '='
};
directive.link = function(scope, element, attrs) {
scope.options = {selected : 0};
scope.$watch(function() {
return scope.options.selected;
}, function(newVal) {
if(newVal===1) {
scope.buttonCaption = {text : 'Edit'};
} else if(newVal === 0) {
scope.buttonCaption = {text : 'Preview'};
}
});
};
return directive;
}]);
And then I pulled {{contentModel}} out to make sure that {{content}} binds in the outer scope:
<div ng-app="myapp">
<data-tc-markdown content-model="content"></data-tc-markdown>
{{content}}
</div>
this seems to work.
The "content" variable should be defined on an outer scope of your directive. For example, see below: I defined content1 and content2 on an outer controller. These contain the values themselves.
http://jsfiddle.net/jajtzyhh/3/
var myapp = angular.module('myapp',[]).controller('MyController', ['$scope', function($scope) {
$scope.content1 = 'Hello';
$scope.content2 = 'World';
}]);
<div ng-app="myapp">
<div ng-controller="MyController">
<data-tc-markdown content-model="content1"></data-tc-markdown>
<data-tc-markdown content-model="content2"></data-tc-markdown>
</div>
</div>
I'm learning the "scope" option in angularjs directives and couldnt figure out why the # isnt working. YOu can check the code http://jsfiddle.net/gerlstar/Lzgts/. The issue is that the second h4 tag is suppose to display "I'm a directive, within the app .. " but it is displaying "Hello world". Any help would be great thanks.
<div ng-controller="MainCtrl">
<div ng-init="title = 'Hello World'">
<h2 id="appTitle">{{title}}</h2>
<button id="newAppTitle" ng-click="setAppTitle('App 2.0')">Upgrade me!</button>
<div my-scoped-directive msd-title="I'm a directive, within the app {{title}}">
<h4 id="directiveTitle">{{title}}</h4>
<button id="newDirTitle" ng-click="setDirectiveTitle('bob')">Bob it!</button>
</div>
</div>
var app = angular.module('mainModule', []);
app.controller('MainCtrl', function ($scope) {
$scope.setAppTitle = function (title) {
$scope.title = title;
};
});
app.directive('myScopedDirective', function () {
return {
scope: {
'title': '#msdTitle'
},
link: function ($scope, $element, $attrs) {
$scope.setDirectiveTitle = function (title) {
$scope.title = title;
};
}
};
});
I'm wondering what's the way to do work this snippet:
//html
<div ng-app="app">
<div ng-controller="AppCtrl">
<a my-dir ng-repeat="user in users">{{user.name}}</a>
</div>
</div>
//js
var app = angular.module('app', []);
app.controller("AppCtrl", function ($scope) {
$scope.users = [{name:'John',id:1},{name:'anonymous'}];
$scope.fxn = function() {
alert('It works');
};
})
app.directive("myDir", function ($compile) {
return {
link:function(scope,el){
el.attr('ng-click','fxn()');
//$compile(el)(scope); with this the script go mad
}
};
});
I know it's about the compile phase
but I don't get the point so a short explanation would be
very appreciate.
A directive which adds another directive to the same element:
Similar answers:
How to get ng-class with $dirty working in a directive?
creating a new directive with angularjs
Here is a plunker: http://plnkr.co/edit/ziU8d826WF6SwQllHHQq?p=preview
app.directive("myDir", function($compile) {
return {
priority:1001, // compiles first
terminal:true, // prevent lower priority directives to compile after it
compile: function(el) {
el.removeAttr('my-dir'); // necessary to avoid infinite compile loop
el.attr('ng-click', 'fxn()');
var fn = $compile(el);
return function(scope){
fn(scope);
};
}
};
});
Much cleaner solution - not to use ngClick at all:
A plunker: http://plnkr.co/edit/jY10enUVm31BwvLkDIAO?p=preview
app.directive("myDir", function($parse) {
return {
compile: function(tElm,tAttrs){
var exp = $parse('fxn()');
return function (scope,elm){
elm.bind('click',function(){
exp(scope);
});
};
}
};
});
You can try this:
<div ng-app="app">
<div ng-controller="AppCtrl">
<a my-dir ng-repeat="user in users" ng-click="fxn()">{{user.name}}</a>
</div>
</div>
<script>
var app = angular.module('app', []);
function AppCtrl($scope) {
$scope.users = [{ name: 'John', id: 1 }, { name: 'anonymous' }];
$scope.fxn = function () {
alert('It works');
};
}
app.directive("myDir", function ($compile) {
return {
scope: {ngClick: '='}
};
});
</script>