I am working on a directive to show a modal. It works the first time through but the second time or anytime after the, the click no longer works. The code looks like this:
<li><a href="http://example.com/JohnDoe" profile-modal="JohnDoe">JohnDoe</li>
EngagementApp.directive('profileModal', ['$compile', 'Request', '$modal', '$q',
function($compile, Request, $modal, $q) {
return {
restrict : 'A',
link : function(scope, element, attrs) {
element.bind('click', function(e) {
e.preventDefault();
scope.modal = {
username : attrs.profileModal,
url : main_site_url
};
var modalPromise = $modal({template: '/templates/profile.html', persist: true, show: false, backdrop: 'static', scope: scope});
$q.when(modalPromise).then(function(modalEl) {
modalEl.modal('show');
});
});
}
};
}]);
How can I get the click to work several times and not just the first time? The framework I'm using for the modal is angularstrap. http://mgcrea.github.io/angular-strap/
Related
Below are the two directive. My problem is that the function addSectorAttributes in my second directive is been fired twice on ng-click from project_subtypes.html.
.directive('projectFilter', function($compile, $timeout){
return {
restrict: 'E',
templateUrl: 'project_filter.html',
link : function(scope,element, attr){
//getting data and fill the html from a service
},
controller: function ($scope) {
$scope.addSubTypes = function (event,id) {
var ex = $(event.currentTarget);
var el = $compile( "<project-subtypes typeid="+id+" class='slide-content'></project-subtypes>" )( $scope );
ex.parent().append(el);
};
}
}
})
.directive('projectSubtypes', function($compile){
return {
restrict: 'E',
scope: true,
templateUrl: 'project_subtypes.html',
link : function(scope,element,attr){
//getting data and fill the html from a service
var id = attr.typeid;
sectorFiltering.getSectorSubTypes(id).success(function(data) {
scope.sector_subtypes = data.sector_subtypes;
});
});
},
controller: function ($scope) {
$scope.addSectorAttributes = function (event,id) {
console.log("teeest"); // called twice.....
};
}
}
})
project_subtypes.html
<li ng-repeat="subtype in substype.subtypes">
<div layout='row' class='load-attributes' ng-click=" addSectorAttributes($event, subtype.id)"></div>
</li>
Any help please....
If the directive function called twice if one time it does not give you the subtype.id and next time if it gives you subtype.id then you just only need to add condition in your directive like as below.
subtype.id&&addSectorAttributes($event, subtype.id)"
Regards,
Mahenrdra
I was just reading here about accessing one directive's controller from within another directive via the require option:
http://jasonmore.net/angular-js-directives-difference-controller-link/
The directive droppable and dashboard declarations in on my view - on two different divs:
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-12" data-droppable drop="handleDrop">
<div id="dash" dashboard="dashboardOptions" class="dashboard-container"></div>
</div>
</div>
However I can't seem to get it to work. My dashboardCtrl param below is NULL.
Here in my droppable directive, I use the REQUIRE option:
.directive('droppable', function () {
return {
scope: {
drop: '&',
},
//****************** dashboard directive is optionally requested ************
require: '?dashboard',
link: function (scope, element, attributes, dashboardCtrl) {
el.addEventListener('drop', function (e) {
if (e.preventDefault) { e.preventDefault(); }
this.classList.remove('over');
var item = document.getElementById(e.dataTransfer.getData('Text'));
this.appendChild(item.cloneNode(true));
// *** CALL INTO THE dashboardCtrl controller ***
dashboardCtrl.addWidgetInternal();
return false;
}, false);
}
}
});
and the dashboard directive :
angular.module('ui.dashboard')
.directive('dashboard', ['WidgetModel', 'WidgetDefCollection', '$modal', 'DashboardState', '$log', function (WidgetModel, WidgetDefCollection, $modal, DashboardState, $log) {
return {
restrict: 'A',
templateUrl: function (element, attr) {
return attr.templateUrl ? attr.templateUrl : 'app/shared/template/dashboard.html';
},
scope: true,
controller: ['$scope', '$attrs', function (scope, attrs) {
// ommitted for brevity
}],
link: function (scope) {
scope.addWidgetInternal = function (event, widgetDef) {
event.preventDefault();
scope.addWidget(widgetDef);
};
};
}
}]);
However, my dashboardCtrl parameter is NULL. Please help me to figure out how to use require.
I actually need to call the addWidget() function, which is within the link option; but I suppose I can copy or move that into the controller option.
thank you !
Bob
Here is an example of "parent" directive dashboard requiring droppable, and communication between the two making use of require and passing dashboardCtrl
Here is a good article to see directive to directive communication
Fiddle example also built from your previous question
JSFiddle
app.directive('droppable', [function () {
return {
restrict: 'A',
require: 'dashboard',
link: function (scope, elem, attrs, dashboardCtrl) {
dashboardCtrl.controllerSpecificFunction('hello from child directive!');
scope.addWidgetInternal = function(message) {
console.log(message);
}
}
}
}]);
app.directive('dashboard', [function () {
return {
restrict: 'A',
controller: function ($scope) {
$scope.handleDrop = function(message) {
$scope.addWidgetInternal(message)
}
this.controllerSpecificFunction = function(message) {
console.log(message);
}
}
}
}]);
Edit
Based on discussion, here is a solution for what I currently understand the problem to be
Parent directive dashboard optionally requires child directive droppable and there needs to be communication between the two
<div dashboard>
<button id="dash" droppable ng-click="handleDrop($event)">Handle Drop</button>
</div>
app.directive('droppable', [function () {
return {
restrict: 'A',
require: '^?dashboard',
link: function (scope, elem, attrs, dashboardCtrl) {
scope.handleDrop = function($event) {
dashboardCtrl.addWidgetInternal($event);
}
}
}
}]);
app.directive('dashboard', [function () {
return {
restrict: 'A',
controller: function ($scope) {
this.addWidgetInternal = function($event) {
console.log($event);
}
}
}
}]);
Updated JSFiddle
I am setting up a <button> that is supposed to open a chat window.
the chat window has a ng-show depending on scope.openChat which is false to start.
When I clicked the button I update scope.openChat to true and use $scope.apply.
The scope seems to have updated but the ng-show does not do anything.
here is the html
<div ng-controller="MessagesCtrl">
<button start-chat>Send Messages</button>
</div>
and
<div ng-show="openChat" ng-controller="MessagesCtrl">
<div>CHAT WINDOW
</div>
</div>
here is the controller:
app.controller("MessagesCtrl", function MessagesCtrl($scope,Auth) {
$scope.openChat = false;
$scope.message = { recipient : undefined, sender: undefined, text:'text'};
});
Here is the directive for the button:
'use strict';
app.directive('startChat',[ 'Post', 'Auth', function (Post, Auth) {
return {
restrict: 'A',
replace: true,
bindToController: true,
controller: 'MessagesCtrl',
link: function(scope, element, attrs) {
element.bind('click', function() {
scope.$apply(function() {
scope.openChat = true;
scope.message.recipient = scope.profile.$id;
scope.message.sender = Auth.resolveUser().uid;
});
});
}
}
}]);
thank you
I'd suggest not creating two instances of MessagesCtrl. Here is a simplified working example of the issue you are trying to solve. Examine the markup and see that MessagesCtrl contains both of these elements. Otherwise, you were on the right track updating $scope and calling $apply
Also note that .on() is the preferred method to .bind() see jQuery docs
JSFiddle Link
<div ng-app="app">
<div ng-controller="MessagesCtrl">
<button start-chat>Send Messages</button>
<div class="chatWindow" ng-show="openChat"></div>
</div>
</div>
app.directive('startChat', [function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.on('click', function() {
scope.$apply(function() {
scope.openChat = true;
});
});
}
}
}]);
app.controller('MessagesCtrl', ['$scope', function($scope) {
$scope.openChat = false;
$scope.message = { recipient : undefined, sender: undefined, text:'text'};
}]);
I'm quite new to AngularJS and I'm trying to understand a few things.
First of all, I have my controller of which I will place a snippet here:
var OfficeUIRibbon = angular.module('OfficeUIRibbon');
// Defines the OfficeUIRibbon controller for the application.
OfficeUIRibbon.controller('OfficeUIRibbon', ['$scope', '$http', function($scope, $http) {
var ribbon = this;
ribbon.setApplicationMenuAsActive = function() {
ribbon.applicationMenuActive = true;
}
}
Then I have a directive:
var OfficeUIRibbon = angular.module('OfficeUIRibbon');
OfficeUIRibbon.directive('ribbonApplicationMenu', function() {
return {
restrict: 'E',
replace: false,
scope: {
data: '#'
},
templateUrl: function(element, attributes) {
return attributes.templateurl;
}
}
});
The directive is called like this:
<ribbon-application-menu templateUrl="/OfficeUI.Beta/Resources/Templates/ApplicationMenu.html" data="/OfficeUI.Beta/Resources/JSon/Ribbon/ribbon.json"></ribbon-application-menu>
This does all work and in my template for the directive, the following is placed:
<div id="application" id="applicationMenuHolder" ng-controller="OfficeUIRibbon as OfficeUIRibbon" ng-show="OfficeUIRibbon.applicationMenuActive"...
From inside another element, when I execute a click a function on my controller is executed:
ng-click="OfficeUIRibbon.setApplicationMenuAsActive()"
Here's the directive from the other element:
OfficeUIRibbon.directive('ribbon', function() {
return {
restrict: 'E',
replace: false,
scope: {
data: '#'
},
templateUrl: function(element, attributes) {
return attributes.templateurl;
}
}
});
This function does change the property "applicationMenuActive" on the ribbon itself, which should make the item in the directive template show up.
However, this is not working. I'm guessing I need to watch this property so the view get's updated accordingly.
Anyone has an idea on how this could be done?
Trying to load the RoyalSlider as a Directive. Here's my directive, which works though I'm not sure exactly why, on first load but not on subsequent loads:
app.directive('royalSlider', ['$timeout', function($timeout) {
$(".royalSlider").royalSlider({
keyboardNavEnabled: true,
arrowsNav: true,
arrowsNavHideOnTouch: true,
imageScaleMode: 'fill',
slidesSpacing: 0
});
}]);
with the error:
TypeError: Cannot read property 'compile' of undefined
Assuming the issue is loading when all content is finished, I changed it to this:
app.directive('royalSlider', ['$timeout', function($timeout) {
return {
link: function ($scope, element, attrs) {
$scope.$on('$viewContentLoaded', function () {
$(".royalSlider").royalSlider({
keyboardNavEnabled: true,
arrowsNav: true,
arrowsNavHideOnTouch: true,
imageScaleMode: 'fill',
slidesSpacing: 0
});
})
}
}
}]);
And Nothing happens. $timeout is also in there because I've tried that trick too, to no avail.
Try this
app.directive('royalSlider', ['$timeout', function($timeout) {
return {
link: function ($scope, element, attrs) {
$scope.$apply($(".royalSlider").royalSlider({
keyboardNavEnabled: true,
arrowsNav: true,
arrowsNavHideOnTouch: true,
imageScaleMode: 'fill',
slidesSpacing: 0
}));
}
}
}]);
Or
app.directive('royalSlider', ['$timeout', function($timeout) {
return {
link: function ($scope, element, attrs) {
$(".royalSlider").royalSlider({
keyboardNavEnabled: true,
arrowsNav: true,
arrowsNavHideOnTouch: true,
imageScaleMode: 'fill',
slidesSpacing: 0
});
$scope.$apply();
}
}
}]);
I already have 2 situations where directives and services/factories didn't play well.
The scenario is that I have (had) a directive that has dependency injection of a service, and from the directive I ask the service to make an ajax call (with $http).
In the end, in both cases the ng-repeat did not file at all, even when I gave the array an initial value.
I even tried to make a directive with a controller and an isolated-scope. Only when I have moved everything to a controller then it worked like magic. One of them was the royal slider.
Here is my code
app.service('AjaxService', ['$log', '$http', function ($log, $http) {
var me = this;
me.CallHttpAjaxAndMapSearch = function (url, targetObjext, propertyName, callback, splitObject) {
$http.get(url)
.success(function(data){
//etc., mapping to selectedArray
if (propertyName) {
targetObjext[propertyName] = selectedArray;
}
else {
targetObjext['selectedArray'] = selectedArray;
}
if (callback) {
callback();
}
});
};
}]);
app.service('slidersService', ['$log', '$http', 'AjaxService', function ($log, $http, AjaxService) {
var me = this;
me.initRoyalSlider = function (url, element, arrayName, sliderOptions, splitObject) {
me[arrayName] = [];
var successCallback = function slidersService_successCallback() {
setTimeout(function slidersService_successCallback_Timeout() {
$log.log('setTimeout for ' + arrayName);
element.royalSlider(sliderOptions);
}, 0);
};
AjaxService.CallHttpAjaxAndMapSearch(url, me, arrayName, successCallback, splitObject);
};
}]);
app.controller('royalSlider', function ($scope, $attrs, $log, slidersService) {
var arrName = $attrs.royalSlider;
var options = JSON.parse($attrs.royalSliderOptions);
var element = $attrs.$$element;
$scope.svc = slidersService;
slidersService.initRoyalSlider($attrs.royalSliderUrl, element, arrName, options, $attrs.splitObject);
});
And the HTML
<div class="slides royalSlider rsMinW "
ng-controller="royalSlider"
royal-slider="mainSlider"
royal-slider-options='{"loop":true,"autoPlay":{"enabled":true,"pauseOnHover":true,"delay":3000},"arrowsNav":false,"controlNavigation":"bullets"}'
royal-slider-url="/_api/search/query?bla bla">
<div ng-repeat="slide in svc.mainSlider">