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>
Related
I have simple scenario with costume directive in angularjs. In which if there will be only one item in drop down it would be selected by default else it work as normal drop down list.
for that I try below code,
var app = angular.module("testapp", []);
(function () {
'use strict';
angular.module('testapp').controller('TestCtrl', ['$scope', TestCtrl]);
function TestCtrl($scope) {
$scope.Test=[];
$scope.Test.id=0;
$scope.data = [{
"id": 1,
"name": "abc"
}];
}
})()
angular.module('testapp').directive('advanceDropdown', function () {
var directive = {}
directive.restrict = 'A';
directive.require = 'ngModel';
directive.scope = {
items: '=advanceDropdown'
}
directive.link = function (scope, element, attrs, ctrl) {
if (scope.items.length == 1) {
element.val(scope.items[0]);
}
}
return directive;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.2/angular.min.js"></script>
<div ng-app="testapp" ng-controller="TestCtrl">
<select name="ddlTest" ng-model="Test.id" ng-options="d.id as d.name for d in data" advance-dropdown="data" required>
<option value="" ng-selected="selected" disabled>--Select--</option>
</select>
</div>
but it can't works. what I missing in the code.
Your code is correct, only a small issue inside directive, try the following please
directive.link = function (scope, element, attrs, ctrl) {
if (scope.items.length == 1) {
element.val = scope.items[0];
}
}
Demo
I have a custom directive to show contents when depending on if it is marked special:-
myApp.directive('actionSpace', function() {
//define the directive object
var directive = {};
//restrict = E, signifies that directive is Element directive
directive.restrict = 'E';
directive.link = function(scope, elem, attr) {
console.log(scope.typeEv);
if(attr.special == "1") {
elem.html("");
} else {
elem.replaceWith('<div class="event-list-control"><button class="event-action-btn" data-ng-click="whoWas()"> '+
'<i class="fas fa-edit"></i>' +
'</button><button class="event-action-btn" data-ng-click="tellMe()">' +
'<i class="fas fa-trash-alt"></i></button></div>');
}
}
return directive;
});
I can see in console directive's parent scope is available (its printing one of the variables), but data-ng-click does not work.
You need to compile the inserted html before inserting it into the element, please refer the below example. I use the $compile method to make the data-ng-click work!
var app = angular.module('myApp', []);
app.controller('MyController', function MyController($scope) {
});
app.directive('actionSpace', function($compile) {
//define the directive object
var directive = {};
//restrict = E, signifies that directive is Element directive
directive.restrict = 'E';
directive.link = function(scope, elem, attr) {
var html = ''
scope.tellMe = function(){console.log("telling");}
scope.whoWas = function(){console.log("this is");}
if(attr.special == "1") {
html = '';
} else {
html = '<div class="event-list-control"><button class="event-action-btn" data-ng-click="whoWas()">'+ '<i class="fas fa-edit"></i>' +
'Who Was</button><button class="event-action-btn" data-ng-click="tellMe()">' +
'<i class="fas fa-trash-alt"></i>Tell Me</button></div>';
}
var el = $compile(html)(scope);
elem.append(el);
}
return directive;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller='MyController' ng-app="myApp">
<action-space></action-space>
</div>
Instead of composing the template in the postLink function, do it in a template function:
myApp.directive('actionSpace', function() {
//define the directive object
var directive = {};
//restrict = E, signifies that directive is Element directive
directive.restrict = 'E';
directive.template = function(tElem, tAttrs) {
if (tAttrs.special == "1") {
return "";
} else {
return `
<div class="event-list-control">
<button class="event-action-btn" data-ng-click="whoWas()">
<i class="fas fa-edit"></i>
</button>
<button class="event-action-btn" data-ng-click="tellMe()">
<i class="fas fa-trash-alt"></i>
</button>
</div>
`;
};
}
return directive;
});
For more information, see AngularJS Comprehensive Directive API Reference - template
I am trying to call a parent function from a directive. But my functions are not being called.
Here is the code for your reference.
Controller
'use strict';
angular.module('myApp')
.controller('MyCtrl', function($scope) {
$scope.iconSelected = function() {
console.log('iconSelected');
var icon = angular.element('#icon').prop('files');
if (!icon) {
return;
}
icon = icon[0];
var _URL = window.URL || window.webkitURL;
$scope.utility.icon = _URL.createObjectURL(icon);
}
$scope.sourceSelected = function() {
console.log('sourceSelected');
var source = angular.element('#source');
console.log(source.prop('files'));
};
});
Directive
'use strict';
angular.module('myApp')
.directive('uploadButton', function() {
return {
templateUrl: 'app/directives/upload-button/upload-button.html',
restrict: 'E',
transclude: true,
scope: {
onSelect: '&'
},
link: function(scope, element, attrs) {
scope.name = attrs.name;
scope.id = attrs.id || attrs.name;
scope.label = attrs.label || attrs.name;
scope.accept = attrs.accept;
scope.showDialog = function() {
element.find('#' + scope.id).trigger('click');
};
element.find('input').change(function() {
scope.$apply(attrs.onSelect);
});
}
};
});
Directive Template
<md-input-container class="upload-button">
<md-button class="md-raised" ng-click="showDialog()">
<span ng-transclude></span>
</md-button>
<input type="file" name="{{name}}" id="{{id}}" aria-label="{{label}}" accept="{{accept}}">
</md-input-container>
Directive Usage
<upload-button name="icon" on-select="iconSelected()" accept=".svg">Choose an icon</upload-button>
<upload-button class="source-btn" name="source" on-select="sourceSelected()" accept=".zip">Select source code</upload-button>
Inside your directive code you are calling onSelect using attrs.onSelect change it to scope.onSelect. attrs.onSelect will just give you the string value iconSelected(). You need the function reference which will be available in the isolated scope which is created by the directive.
element.find('input').change(function() {
scope.$apply(scope.onSelect);
});
The code below wraps a KendoWindow in a directive. The objective is twofold: (1) to open/close KendoWindow via $broadcast and avoid having window open/close methods in the controller (as these methods modify the DOM and not the model), and (2) use transclusion to define in the component child elements that will be shown in the KendoWindow and handled in the controller.
The problem is that the elements don't show up in the KendoWindow (see plunk) and the drow down list doesn't work. What's wrong with this code?
HTML:
<button ng-click="open()">Open window</button>
<button ng-click="close()">Close window</button>
<div my-window title="'This is the title'">
<p>Some HTML content</p>
This is a link
<select kendo-drop-down-list="ddl" style="width: 200px" k-options="ddlOptions">
<option>xxx</option>
<option>yyy</option>
<option>zzz</option>
</select>
</div>
Javascript:
var app = angular.module("app", [ "kendo.directives" ]);
function MyCtrl($scope) {
$scope.open = function () {
$scope.$broadcast('open');
};
$scope.close = function () {
$scope.$broadcast('close');
};
$scope.ddlOptions = {
select: function() {
alert('selected');
}
};
}
app.directive('myWindow', function() {
var directive = {};
directive.restrict = 'AE';
directive.transclude = true;
directive.scope = { title: '=' };
directive.template = '<div kendo-window="win" k-width="500" k-visible="false" ng-transclude></div>';
directive.link = function(scope, element, attrs) {
var init = function() {
scope.win.title(scope.title);
};
scope.$on("open", function(){
scope.win.center();
scope.win.open();
});
scope.$on("close", function(){
scope.win.close();
});
scope.$on("kendoWidgetCreated", function(event, widget){
if (widget === scope.win ) {
init();
}
});
};
return directive;
});
I have a directive defined like so:
angular.module('directives.myInput', [])
.directive('myInput', function($parse, $http, $sce){
return {
restrict: 'E',
template: '<input type="text" ng-model="searchStr" />',
controller: function($scope){
$scope.keyPressed = function(event){
$scope.showDropdown = true;
.
.
.
}
}
};
});
And then I have a button in html and directive above declared like so:
<div ng-controller="IndexCtrl">
<button ng-click="startNewLog()">Start</button>
<div ng-controller="ItemNewCtrl">
<myInput />
</div>
</div>
I want to change/initialize ng-model="searchStr" model on a button ng-click. How can I do that?
Thanks guys,
Jani
If I understand you right, first of all you need call child controller with $broadcast. Since we don't use isolate scope, we just call directive method from child controller:
[Short answer]
No isolate scope example
Demo 1 Fiddle
For isolate scope, I would map value to directive that listens on value change automatically:
Isolate scope example
Demo 2 Fiddle
[Full answer]
No isolate scope example
HTML
<div ng-controller = "IndexCtrl">
<button ng-click="startNewLog()">Start</button>
<div ng-controller="ItemNewCtrl">
<my-input></my-input>
</div>
</div>
JS
var app = angular.module('myModule', []);
app.controller('IndexCtrl', function ($scope) {
$scope.startNewLog = function(){
$scope.$broadcast('someEvent');
};
});
app.controller('ItemNewCtrl', function ($scope) {
$scope.$on('someEvent', function() {
$scope.callDirective();
});
});
app.$inject = ['$scope'];
app.directive('myInput', function(){
return {
restrict: 'E',
template: '<input type="text" ng-model="searchStr" />',
controller: function($scope){
$scope.searchStr;
$scope.keyPressed = function(event){
$scope.showDropdown = true;
}
},
link: function(scope, elm, attrs) {
scope.callDirective = function() {
scope.searchStr = 'callDirective';
};
}
};
});
Isolate scope example
HTML
<div ng-controller = "IndexCtrl">
<button ng-click="startNewLog()">Start</button>
<div ng-controller="ItemNewCtrl">
<my-input my-model='contInput'></my-input>
</div>
</div>
JS
var app = angular.module('myModule', []);
app.controller('IndexCtrl', function ($scope) {
$scope.startNewLog = function(){
$scope.$broadcast('someEvent');
};
});
app.controller('ItemNewCtrl', function ($scope) {
$scope.contInput = '';
$scope.count = 0;
$scope.$on('someEvent', function() {
$scope.contInput = 'hey mate';
});
});
app.$inject = ['$scope'];
app.directive('myInput', function(){
return {
restrict: 'E',
scope:{searchStr: '=myModel'},
template: '<input type="text" ng-model="searchStr" />',
controller: function($scope){
$scope.searchStr;
$scope.keyPressed = function(event){
$scope.showDropdown = true;
}
}
};
});