I am trying to make a resizable dialog, like this: DEMO.
.directive("dialog", function() {
return {
restrict: 'E',
replace: true,
scope: {},
templateUrl: 'dialog-template.html',
controller: function($scope, $element) {
$scope.movabled = true;
$scope.dialogElem = $element;
},
link: function(scope, iElem, iAttrs) {
/* ...... */
scope.$watch(function() {
var width = scope.dialogElem.outerWidth(),
height = scope.dialogElem.outerHeight();
return [width, height];
}, function(nValue) {
console.log(nValue);
var width = nValue[0], height = nValue[1],
content = scope.dialogElem.find('.content');
content.css('height', height-84);
content.find('.left-panel')
.css('width', width-110)
.css('height', height-84);
content.find('.right-panel')
.css('height', height-84);
}, true);
}
};
})
But angularjs watch event did not trigger when I expand dialog.
So, how can I $watch transition-property with angularjs?
Related
app.directive("itemsContainer", function() {
return {
restrict: "E",
controllerAs: "itc",
bindToController: true,
controller: function() {
this.showItems = false;
this.items = null;
this.loadItems = (data) => {
this.items = data;
this.showItems = true;
}
this.hideSummary = () => {
this.showItems = false;
}
},
templateURL:'itemsContainer.html'
};
});
app.directive("itemsSummary", function() {
return {
restrict: "E",
require: "^itc",
link: function(scope, element, attrs, ctrl) {
scope.showSummary = ctrl.showItems;
scope.items = ctrl.items;
},
templateURL:'itemsSummary.html'
};
});
app.directive("itemsList", function() {
return {
restrict: "E",
require: "^itc",
scope: {
items = "="
},
link: function(scope, element, attrs, ctrl) {
if(items !== null)
{
ctrl.loadItems(items);
}
scope.hideSummary = () => {
ctrl.hideSummary();
}
},
templateURL:'itemsList.html'
};
});
<itemsContainer>
<itemsSummary>{{itemsSummary}}</itemsSummary>
<itemsList>{{items}}</itemsList>
</itemsContainer>
Here, when itemsList directive set the Hide summary using itemsContainer controller, which is not updated in itemsSummary?
how to make all the three directive in sync?
Best way to communicate between sibling directive?
Currently am doing with Event emit which I don't want to do.
I need a best practice solution.
My requirement:
<parent>
<child1></child1>
<child2></child2>
</parent>
How to communicate any update in child2 to child1?
You need to do manual transclution, that's what I did in a similar situation. Anglers default transclution won't work, since it creates a new scope.
<itemsContainer>
<itemsSummarydata="$ctrl.data"></itemsSummary>
</itemsContainer>
/** * Parent component */
angular.module("app").component("itemsContainer", function() {
constructor() {
return {
restrict: 'E',
replace: true,
template: "<div transclude-extended></div>",
transclude: true,
bindToController: true,
controller: function () {
var ctrl = this;
ctrl.data = 'This is sample data.';
}
};
}
});
/** * Transclude Extended Directive */
angular.module("app").directive("transcludeExtended", function(){
constructor() {
return {
link: function ($scope, $element, $attrs, controller, $transclude) {
var innerScope = $scope.$new();
$transclude(innerScope, function (clone) {
$element.empty();
$element.append(clone);
$element.on('$destroy', function () {
innerScope.$destroy();
});
});
}
}
};
});
transcludeExtended is the manual way of doing the translation, instead of ng-transclude
Reference: https://github.com/angular/angular.js/issues/1809
I want to create a cascading dropdown directive .
<my-dropdown label="states" url="http://statelisturl">
<my-dropdown label="cities" url="http://citylisturl">
</my-dropdown>
</my-dropdown>
But states will be list first, when I select a state cities will be get from url.
Is this possible for angularjs technically? Or I should be seperated directive for every dropdown?
You could do something like this:
.directive("myDropdown", function() {
return {
restrict: "E",
require: ["myDropdown", "?^^myDropdown"],
template: "<select ng-options='opt as opt.label for opt in $ctrl.options' ng-model='$ctrl.selectedOption' ng-change='$ctrl.changed($ctrl.selectedOption)'></select><div ng-transclude></div>",
scope: true,
bindToController: {
url: "#",
label: "#"
},
controller: function($scope, $http) {
var _self = this;
_self.init = function() {
$http.get(_self.url).then(function(response) {
_self.options = response.data;
});
}
_self.parentChanged = function(item) {
var id = item.id;
$http.get(_self.url + "?id=" + id).then(function(response) {
_self.options = response.data;
});
}
},
link: function(scope, element, attrs, ctrls) {
var ctrl = ctrls[0];
var parentCtrl = ctrls[1];
if (parentCtrl) {
scope.$watch(function() {
return parentCtrl.selectedOption;
}, function(newval) {
if (newval) {
ctrl.parentChanged(newval);
}
});
} else {
ctrl.init();
}
},
controllerAs: "$ctrl",
transclude: true
}
});
EDIT: I have a working example here
I want to accomplish scroll-able content by clicking on Bootstrap module. Its working fine. This is following code of my directive:
'use strict';
angular.module('cbookApp')
.directive('scrollTo', scrollTo);
scrollTo.$inject = ['$anchorScroll'];
function scrollTo($anchorScroll) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.bind('click', function (event) {
event.stopPropagation();
var location = attrs.scrollTo;
if (scope.vm.isEdit || typeof scope.vm.isEdit =="undefined" ) {
$anchorScroll(location);
} else {
$anchorScroll(location+'1');
}
});
}
};
}
But only problem is i am not sure how to apply active class to current affix li. This DEMO way i found to apply class active to current li and remove from other. It was working without Controller as but once i added controller as it stopped working and give some error of scope.
var app = angular.module('app', ['directives']);
app.controller('firstController',[function(){
var vm = this;
vm.model = { value: 'dsf'};
}]);
angular.module('directives', []).directive('toggleClass', function () {
var directiveDefinitionObject = {
restrict: 'A',
template: '<span ng-click="localFunction()" ng-class="selected" ng-transclude></span>',
replace: true,
bindToController: true,
scope: {
model: '='
},
transclude: true,
link: function (scope, element, attrs) {
scope.localFunction = function () {
scope.model.value = scope.$id;
};
scope.$watch('model.value', function () {
if (scope.model.value === scope.$id) {
scope.selected = "active";
} else {
scope.selected = '';
}
});
}
};
return directiveDefinitionObject;
});
Can you please add this in your directive.
element.parent().parent().children().each(function() {
$(this).find('a').removeClass('active');
});
element.addClass('active');
http://jsfiddle.net/hngzxmda/1/
I suggest using controllerAs in your directive too
angular.module('directives', []).directive('toggleClass', function () {
var directiveDefinitionObject = {
restrict: 'A',
template: '<span ng-click="vmd.localFunction()" ng-class="selected" ng-transclude></span>',
replace: true,
bindToController: {
model: '=',
$id: '='
},
scope: {},
transclude: true,
controller: function() {
var _this = this;
this.localFunction = function () {
_this.model.value = _this.$id;
};
},
controllerAs: 'vmd'
};
return directiveDefinitionObject;
});
I have two angularjs directives (extWindow and taskBar) and want to inject taskBar's controller into extWindow in order to access it's scope. Because they don't share the same scope I used
require : '^$directive'
syntax to include it.
Doing so I could get rid of the error 'Controller 'taskBar', required by directive 'extWindow', can't be found!' but TaskBarCtrl is still undefined in link(..) method of the extWindow directive.
Any suggestions how to fix it?
var mod = angular.module('ui', [])
.directive('taskBar', function() {
var link = function(scope, el, attrs) {
$(el).css('display', 'block');
$(scope.titles).each(function(i,t) {
el.append('<span>' + t + '</span>')
});
};
return {
scope: {},
restrict : 'E',
controller: function($scope, $element, $attrs) {
$scope.titles = [];
this.addTitle = function(title) {
$scope.titles.push(w);
};
this.removeTitle = function(title) {
$scope.titles = jQuery.grep(function(n,i) {
return title != n;
});
}
},
link: link
};
}).directive('extWindow', function() {
return {
scope: {},
require: '^?taskBar',
restrict: 'E',
transclude: true,
template: '<div class="ui-window">\
<div class="ui-window-header"><span>{{windowTitle}}</span><div class="ui-window-close" ng-click="close()">X</div></div>\
<div class="ui-window-content" ng-transclude></div>\
</div>',
link: function(scope, element, attrs, taskBarCtrl) {
scope.windowTitle = attrs['windowTitle'];
scope.close = function() {
$(element).css('display', 'none');
}
//taskBarCtrl is not recognized!!!
taskBarCtrl.addTitle(scope.windowTitle);
}
}
});
http://jsfiddle.net/wa9fs2nm/
Thank you.
golbie.
If you have a controller for your parent directive and you need something like.
this.scope = $scope;
this.attrs = $attrs;
And in your in you link function for the child you need something like
var Ctrl = ctrl || scope.$parent.tBarCtrl;
Here's a Plunker
I'm trying to pass a value to a directive. The directive is used to integrate a jquery plugin Knob
JSFIDDLE: http://jsfiddle.net/Tropicalista/TH87t/93/
I have this code:
var App = angular.module('Knob', []);
App.controller('myCtrl', function($scope) {
$scope.number = 24;
})
App.directive('knob', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
$(element).knob().val(scope.number);
console.log(attrs)
}
};
});
The problem is that knob() doesn't return the element. Use this instead:
link: function(scope, element, attrs) {
$(element).val(scope.number).knob();
}
Here's your fiddle: http://jsfiddle.net/TH87t/94/
I used your question as reference for a fully bi-direction binding. For a working version with angular 1.2.1 see http://jsfiddle.net/sander_van_dam/m5YJu/
App.directive('knob', function() {
return {
require: 'ngModel',
scope: { model: '=ngModel' },
controller: function($scope, $element, $timeout) {
var el = $($element);
$scope.$watch('model', function(v) {
var el = $($element);
el.val(v).trigger('change');
});
},
link: function($scope, $element, $attrs,$ngModel) {
var el = $($element);
el.val($scope.value).knob(
{
'change' : function (v) {
$scope.$apply(function () {
$ngModel.$setViewValue(v);
});
}
}
);
}
}
});