I wrote a directive which looks like this:
on parent html:
<cl-sort-n-reverse flip-reverse="flipReverse()" set-key="setKey(key)" sort-key="sortKey" rev="reverse" key="body" title="Content"></cl-sort-n-reverse>
in directive js:
.directive('clSortNReverse', function () {
return {
restrict: 'E',
scope:{
innerKey : '#key',
title : '#title',
inReverse: '=rev',
sortKey:'=',
flipReverse:'&',
setKey:'&'
},
transclude :true,
templateUrl:'../devhtml/common/sortNReverse.html',
link: function (scope, element, attrs) {
}
};
});
in template:
<span>
<div class="btn" ng-if="sortKey!=innerKey" data-ng-click="setKey({key:innerKey});">
{{title}}
</div>
<div class="btn" ng-if="sortKey==innerKey" data-ng-click="flipReverse();">
<b>{{title}}</b>
<i ng-if="inReverse===true" class="fa fa-caret-up"></i>
<i ng-show="inReverse===false" class="fa fa-caret-down"></i>
</div>
</span>
I would really like to be able to insert both functions ans scope level vars like sortKey and reverse to attribute inside one object I can declare in my controller. the answers I found here regarding adding objects to directive attributes all dealt with a simpler case in which the objects encapsulates only simple string or numbers. I'm stumped at how to define that options objects to include $scope level stuff
Is this what you meant?
In your controller:
$scope.sortReverseConfig = {
flipReverse: function() {...},
setKey: function(key) {...},
sortKey: '',
innerKey: $scope.body,
inReverse: $scope.reverse,
title: $scope.content
}
In your html:
<cl-sort-n-reverse config="sortReverseConfig"></cl-sort-n-reverse>
Directive:
.directive('clSortNReverse', function () {
return {
restrict: 'E',
scope:{
config: '='
},
transclude :true,
templateUrl:'../devhtml/common/sortNReverse.html',
link: function (scope, element, attrs) {
}
};
});
Directive template:
<span>
<div class="btn" ng-if="config.sortKey != config.innerKey" data-ng-click="config.setKey({key:config.innerKey});">
{{config.title}}
</div>
<div class="btn" ng-if="config.sortKey == config.innerKey" data-ng-click="config.flipReverse();">
<b>{{config.title}}</b>
<i ng-if="config.inReverse === true" class="fa fa-caret-up"></i>
<i ng-show="config.inReverse === false" class="fa fa-caret-down"></i>
</div>
</span>
Related
I have created a directive which contains a map of key value pairs. In edit mode i used to populate the values of entries using ng-repeat, Also a user can add more key value pairs when he press a add button
Below is the code
angular.module('key_value_component',
[])
.directive('keyValuePairs', function ($compile, $templateCache) {
return {
templateUrl: 'key_value.tpl.html',
restrict: 'E',
replace: true,
scope: {
entries: "=ngModel"
},
controller: function ($scope) {
$scope.create_key_value = function () {
$scope.$broadcast('ready-to-render');
}
}
};
})
.directive("keyValueInit", function ($compile, $templateCache) {
return {
templateUrl: 'key_value_init.tpl.html',
restrict: 'E',
replace: true,
link: function (scope, element, attributes) {
scope.$on('ready-to-render', function (event) {
list_select = $compile($templateCache.get("key_value_input.tpl.html"))(scope);
element.parents('.key_value_element').append(list_select);
})
}
}
}).directive("keyValue", function ($compile, $templateCache) {
return {
templateUrl: 'key_value_input.tpl.html',
restrict: 'E',
replace: true,
}});
templates :
key_value_tpl.html
<div class="container-fluid">
<div class="key_value_header">
<button class="btn btn-success btn-add pull-right" type="button" ng-click="create_key_value()">
<span class="glyphicon glyphicon-plus"></span>
</button>
<div class="col-sm-4"><strong>key</strong></div>
<div class="col-sm-4"><strong>value</strong></div>
</div>
<div class="key_value_body">
<key-value ng-repeat="(key,value) in entries"></key-value>
<div class="key_value_element">
<key-value-init></key-value-init>
</div>
</div>
key_value_input.tpl.html
<div class="form-group key_value">
<div class="col-sm-4">
<input class="form-control key_value_key" type="text" ng-value="key" ng-readonly="key"/>
</div>
<div class="col-sm-4">
<input class="form-control key_value_value" type="text" ng-value="value" ng-readonly="value"/>
</div>
<input-remove-button></input-remove-button>
key_value_init.tpl.html
<div></div>
If someone add a new key value pair I want to append its value in entries. A submit event is happening outside the directive in the form. the directive is part of that form.
Here is my directive:
.directive('iframeOnload', function() {
return {
restrict: 'A',
link: function(scope, elem){
var spinnerElement = angular.element(' <div id="appApprovalSpinner" class="row text-center approve-spinner"><i class="fa fa-spinner fa-pulse fa-5x fa-fw margin-bottom"></i></div>');
elem.replaceWith(spinnerElement);
angular.element('#appApprovalSpinner').addClass('ng-show');
elem.on('load', function(){
angular.element('#appApprovalSpinner').addClass('ng-hide');
});
}
};
});
and here is my html file where to use the directive
<div iframe-onload ></div>
<iframe id="appApprovedId" ng-if="approvalUrl" class="approve-iframe" ng-class="{'app-approved': isAppApproved}" ng-src="{{trustedApprovalUrl}}" iframe-onload></iframe>
I only want to replace the
<div iframe-onload ></div>
with
<div id="appApprovalSpinner" class="row text-center approve-spinner"><i class="fa fa-spinner fa-pulse fa-5x fa-fw margin-bottom"></i></div>'
and keep the iframe as it is because I want onLoad event is called when the iframe is finished loading.
Any suggestion how to replace on the only the div tag but not iframe tag.
Thanks
Instead of doing so much DOM manipulation, you can do this easily with ng-show and ng-hide, and keep track of things with a $scope variable that is assigned by the directive.
Change your directive a bit:
.directive('iframeOnload', function() {
return {
restrict: 'A',
link: function(scope, elem){
scope.ShowSpinner = true;
var spinnerElement = angular.element('<div ng-show="ShowSpinner" class="row text-center approve-spinner"><i class="fa fa-spinner fa-pulse fa-5x fa-fw margin-bottom"></i></div>');
elem.append(spinnerElement);
elem.on('load', function(){
scope.ShowSpinner = false;
});
}
};
});
I made the following changes
Directive:
.directive('iframeOnload', function() {
return {
restrict: 'A',
scope: {
isRequired: '='
},
link: function(scope, elem){
var spinnerElement = angular.element(' <div ng-if="isApprovalRequired" id="appApprovalSpinner" class="row text-center approve-spinner"><i class="fa fa-spinner fa-pulse fa-5x fa-fw margin-bottom"></i></div>');
if ( (angular.element(elem).hasClass('spinner')) && scope.isRequired ) {
elem.replaceWith(spinnerElement);
}
angular.element('#appApprovalSpinner').addClass('ng-show');
elem.on('load', function(){
angular.element('#appApprovalSpinner').addClass('ng-hide');
});
}
};
});
and in the html file I have this
<div class="spinner" iframe-onload is-required="isApprovalRequired"></div>
<iframe id="appApprovedId" ng-if="approvalUrl" class="approve-iframe" ng-class="{'app-approved': isAppApproved}" ng-src="{{trustedApprovalUrl}}" iframe-onload></iframe>
It worked but still need the in there. Note It won't work if there is no tag there
Any solution to make it works without the extra tag ?
I have a template as following header, body(ng-transclude), footer
<div class="wfm-modal">
<div class="modal-header">
<button type="button" id="close-button" class="close" ng-click="cancel()" aria-label="Close"
ng-show="allowClose">
</button>
<h3 class="modal-title">{{title}}</h3>
</div>
<ng-transclude></ng-transclude>
<div class="modal-footer">
<div class="button-row text-right">
<!-- Save button -->
<button id="save" type="submit" ng-click="save()" class="btn btn-primary">
<span ng-if="saveLabel">
{{saveLabel}}
</span>
</button>
</div>
</div>
</div>
As you can see I have a wfm-modal which contains header body(which is ng-transclude) and footer.
My directive:
app
.directive('wfmModal', function ($window, $timeout, _, $log, $compile, $templateCache) {
'use strict';
var link = function (scope, element, attr, controller, transclude) {
transclude(scope.$parent, function(clone, scope) {
element.empty();
element.append(clone);
});
};
return {
restrict: 'E',
link: link,
templateUrl: 'directives/wfmModal/wfmModal.tpl.html',
replace: true,
transclude: true,
scope: {
title: '=',
allowClose: '=',
cancel: '=',
save: '=',
saveLabel: '#',
delete: '='
//delete: '=',
//deletePopover: '#'
}
};
})
My problem: when I dont add the
transclude(scope.$parent, function(clone, scope) {
element.empty();
element.append(clone);
});
to link function then the scope of the body(the content of ng-transclude) is empty on the save that done from the footer(the directive) not from the code of the ng-transclude
when I add this transclude(scope, function...) without the line: element.empty(); then the body the content of ng-transclude is duplicated,
when I add element.empty(); then the header and the footer are disappeared and only the content of ng-transculde is displayed.
I want to connect the scope of ng-transclude to the directive's scope without disrupt the UI
In directive's link function add:
link = function (scope, element, attr, controller, transclude) {
transclude(scope.$parent, function(clone, scope) {
var el = element.find('.wfmBody');
el.append(clone);
});
In html file instead of ng-transclude add:
<div class="wfmBody"></div>
I want to make a reusable modal-window-directive (i found a pair modal-window examples, but that's not what i want, or they do not work properly).
It should look something like this:
(1) title-, body-text and function-name (for the function, which is binded to the action-button in the template) are defined directly within directive
<my-modal
modal-title="Modal Window Title"
modal-body="This is my Modal Window Body"
click-main-html-action-button="myControllerActionFunction()">
</my-modal>
(2) The HTML-template for modal window must pick up the corresponding values
<div class="panel-default">
<div class="panel-heading">
{{title}}
</div>
<div class="panel-body">
<div class="row">
<div class="form-group col-sm-12">**{{body}}**</div>
</div>
<div class="col-sm-12 text-center">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" data-ng-click="templatestartaction(); $event.stopPropagation()">Start action</button>
</div>
</div>
</div>
(3) Button-function for modal window must be defined In the controller
app.controller('controller', function($scope) {
scope.title = "";
scope.body = "";
$scope.myControllerActionFunction = function () {
console.log('myControllerActionFunction', title);
};
})
The question is: how can I read the attrs values from (1)
(modal-title = "Modal Window Title", etc.) and the function name
(click-main-html-button action = "myControllerActionFunction ()") and
pass it to the model and function definition in the controller
(3), so that it is displayed in the html-template (2)?
I can read the attributes from (1), but I do not know how i pass it in controller.
(4)
app.directive('myModal', function () {
return {
transclude: true,
restrict: 'E',
//template: '<div ng-transclude></div>',
templateUrl: "directives/modal/view/modalWindowTemplate.html"
scope: {
templatestartaction: '&clickMainHtmlActionButton'
},
link: function (scope, element, attrs) {
scope.title = attrs.modalTitle;
scope.body = attrs.modalBody;
}
};
});
You need to define title and body in the controller like
$scope.modalProps = {
title: 'My modal title',
body: 'My modal body'
};
Use this in the html
<my-modal
modal-title="modalProps.title"
modal-body="modalProps.body"
click-main-html-action-button="myControllerActionFunction()">
</my-modal>
And define it for the directive
app.directive('myModal', function () {
return {
transclude: true,
restrict: 'E',
//template: '<div ng-transclude></div>',
templateUrl: "directives/modal/view/modalWindowTemplate.html"
scope: {
templatestartaction: '&clickMainHtmlActionButton'
title: '=modalTitle',
body: '=modalBody'
},
...
I try to make the directive with dynamic template
app.directive('boolInput', function () {
'use strict';
var
restrict = 'E',
replace = true,
template = '<ng-include src="template"></ng-include>',
scope = {
value: "=",
template: "#"
},
link = function (scope, element, attributes) {
// some stuff
};
return {
link: link,
restrict: restrict,
replace: replace,
template: template,
scope: scope,
transclude: true
};
});
So I use
template = '<ng-include src="template"></ng-include>'
and
scope = {
//..
template: "#"
}
to pass template url via attribute. All work great instead of one thing. There is how I use directive:
<bool-input data-value="item.value" data-ng-repeat="item in source" data- template="templates/boolInput.html">
{{item.Text}}
</bool-input>
{{item.Text}} - should be transcluded into template
That template:
<div class="checkbox">
<label class="checkbox-custom" ng-transclude>
<input type="checkbox">
<i class="icon-unchecked checked"></i>
</label>
</div>
but this does not happen, as a result I see:
<ng-include src="template" data-value="item.value" data-ng-repeat="item in data" data-template="templates/boolInput.html" class="ng-scope"><div class="checkbox ng-scope">
<label class="checkbox-custom" ng-transclude="">
<input type="checkbox">
<i class="icon-unchecked checked"></i>
<!-- There should be the text -->
</label>
</div></ng-include>
This was 2 years ago... For now we can pass a attribute to templateUrl function
templateUrl: function (elememt, attrs) {
return attrs.template || '<some default template path>';
}