In this plunk I have an Angular UI modal with an alert popup that should display the modal height. Instead, it shows an empty variable. Where's the error?
HTML
<div the-modal></div>
Javascript
var app = angular.module("app", ['ui.bootstrap']);
app.controller("ctl", function($scope, $compile) {});
app.directive("theModal", function($uibModal, $timeout) {
return {
restrict: "AE",
scope: true,
link: function(scope, element, attrs, ctrl, transclude) {
scope.instance = $uibModal.open({
animation: false,
scope: scope,
template: 'Some Text',
appendTo: element
});
$timeout(function(){
alert("Modal height is: " + element.css("height"));
},500);
}
}
});
The content has been placed inside div with modal-dialog class inside directive modal placeholder element. So ideally you should be looking at element's inner modal-content class.
element[0].querySelector('.modal-dialog').offsetHeight
Related
I have the following directive:
app.directive("mydirective", ['$compile', function($compile) {
function link(scope, element, attrs, ctrl, $transclude) {
var actionBtnHTML = `<button type="submit" ng-show="show"></button>`;
element.parent().append(actionBtnHTML);
$compile(element)(scope);
}
return {
restrict: 'A',
scope: {},
link: link,
controller: ['$scope', function MyDirectiveController($scope) {
$scope.show = true;
}]
}]);
My directive simply adds a button after the HTML tag with the mydirective attribute.
I want that the added HTML has the same scope as the directive (ie. the new isolated scope). But it is not the case in this configuration. I guess this is because the added HTML is outside the directive HTML tag.
Whence my question, how can I apply the isolated scope of my directive on the template appended to parent element?
You can use ngTransclude to insert the extra HTML content while keeping the same scope of the directive.
directive("mydirective", ['$compile', function($compile) {
return {
restrict: 'A',
scope: {},
controller: ['$scope', function MyDirectiveController($scope) {
$scope.show = true;
}],
transclude: true,
template: '<ng-transclude></ng-transclude>' +
' <button type="submit" ng-show="show">Submit!</button>'
}
}])
Here's a demo fiddle for your directive!
I'm trying to use popover for multiple instances using one controller and directive. The problem I'm running into is trying define an isolated scope for use in managing the content and state of the popover.
The issue is, I click to open the popover for 'My Content 01' and both popovers are opening up and both show the content from the second popover (My Content 02). Trying to get both to use their own scope and not the shared scope.
Here's my html markup:
<a class="helpful-tip"
data-my-popover
data-popover-label=""
data-uib-popover-template="dynamicPopover.templateUrl"
data-content="<p>My Content 01</p>"
data-popover-is-open="popoverState"
data-popover-trigger="outsideClick"
data-popover-placement="bottom">
<a class="helpful-tip"
data-my-popover
data-popover-label=""
data-uib-popover-template="dynamicPopover.templateUrl"
data-content="<p>My Content 02</p>"
data-popover-is-open="popoverState"
data-popover-trigger="outsideClick"
data-popover-placement="bottom">
Here's my controller:
angular.module('project.components.common.directives.myPopover', [
'ui.bootstrap'
])
.controller('myPopoverCtrl', function($scope, $rootScope) {
$scope.dynamicPopover = {
template: '<button type='button'
id='close'
class='close'
data-ng-show="true"
data-ng-click='tt_popoverState=false'> × </button><br>
<span data-ng-bind-html="htmlContent"></span>'
};
})
.directive('myPopover', function ($sce, $compile) {
return {
restrict: 'A',
template: '<span>{{ label }}</span>',
transclude: true,
controller: 'myPopoverCtrl',
link : function ($scope, element, attrs, ctrl, transclude) {
$scope.popoverState = false;
$scope.label = attrs.popoverLabel;
$scope.htmlContent = $sce.trustAsHtml(attrs.content);
element.append(transclude());
console.log(attrs);
}
};
});
https://angular-ui.github.io/bootstrap/ -> Popover
https://github.com/angular-ui/bootstrap/tree/master/src/popover
I have a directive that works correctly when RequireJS is not used, and I'm trying to migrate it to an application based on RequireJS.
The directive wraps an Angular UI modal, and uses transclude to populate the modal elements (modal elements are defined in the controller that declares the directive). The problem is that if loaded with RequireJS, the modal does not show ANY elements (i.e. it's empty).
This is the plunk of the directive that works correctly without RequireJS. You will see a modal populated with elements.
This is the plunk of the directive that is loaded with RequireJS. You will see that the modal is empty.
There are no errors thrown when the modal is displayed empty, so I'm not sure how to tackle this problem. Any help will be greatly appreciated.
This is the directive:
define(['app','uiBootstrap'], function (app) {
'use strict';
app.directive("theModal", function($timeout,$uibModal) {
return {
restrict: "AE",
scope: {
control: '='
},
transclude: true,
link: function (scope, element, attrs, ctrl, transclude) {
scope.control = scope.control || {}
scope.control.openModal = function () {
var instance = $uibModal.open({
animation: false,
scope: scope,
windowClass: 'the-modal',
template: '<div>in the template</div><div class="content"></div>',
appendTo: element
});
$timeout(function (){
transclude(scope.$parent, function(clonedContent){
element.find('.content').append(clonedContent);
})
},10);
};
}
}
});
});
And this is how I invoke it:
<div ng-controller="ctl">
<button ng-click="open()">open it!</button>
<div the-modal control="modalCtl">
<p>some text</p>
<input type="text" ng-model="input1" />
</div>
</div>
The issue is you have circular dependency. The app needs your modal module to display things correctly, but your modal directive needs that app. The solution is to load your modal directive into a separate module.
Define a separate Angular Module for Modal
// contents of modal.js (remove app dependency)
define(['uiBootstrap'], function () {
'use strict';
var mod = angular.module('modal', ['ui.bootstrap']);
mod.directive("theModal", function($timeout, $uibModal) {
return {
restrict: "AE",
scope: {
control: '='
},
transclude: true,
link: function (scope, element, attrs, ctrl, transclude){
// removed code for brevity
}
}
});
mod.directive("theButton", function($timeout) {
return {
restrict: "AE",
scope: {
control: '='
},
transclude: true,
link: function (scope, element, attrs, ctrl, transclude){
// removed code for brevity
}
}
});
return mod;
});
Make app depend on Modal
// contents of app.js
define([
'angular',
'uiBootstrap',
'uiRouter',
'modal' // <--- the modal.js directive
], function (angular) {
'use strict';
return angular.module('app', ['ui.bootstrap','ui.router', 'modal']); // <--- also add it here
});
I have couple of links in the header. But the pop-up nested under the other controller. I am using a service call for the pop-up here.
clicking on the header link, how can i open the pop-up which nested in the other controller.
And i need to update the content of the pop-up according to the link what the user clicks. for that, i included the html (using ng-include)
here is my code and demo :
var app = angular.module('myApp', []);
app.service('modalService', function() {
this.width = 100;
this.height = 100;
});
app.directive('modalDialog', function(modalService) {
return {
restrict: 'E',
scope: {
show: '='
},
replace: true, // Replace with the template below
transclude: true,
link: function(scope, element, attrs) {
},
templateUrl: "modal.html"
};
});
app.controller('MyCtrl', ['$scope', function($scope, modalService) {
$scope.modalShown = false;
}]);
app.controller('header', ['$scope', 'modalService', function($scope, modalService) {
$scope.modalShown = false;
$scope.toggleModal = function(link) {
console.log(link);
$scope.linkInfo = link+'.html';
$scope.modalShown = !$scope.modalShown;
};
}]);
Live demo
In case the way what i do is wrong, please correct me. at present the fuction is calls and gettting console. but pop-up not opening with appropriate content.
You can use the modal service of angular-UI library angular-ui#modal
If you want to just create something simple, you have to change your code in following ways:
I would recommend using ngIf for showing/hiding your modalDialog directive. With it, it will be rendered when the expression becomes truthy and you can get the right template each time.
Do not transclude since you don't have static templates. You have to compile the template on runtime (using $compile service). Also create a new scope for that template.
app.directive('modalDialog', function(modalService, $rootScope, $compile, $templateCache) {
return {
restrict: 'E',
scope: {
show: '=',
templateUrl: '='
},
link: function(scope, element, attrs) {
var template = $templateCache.get(scope.templateUrl);
var modalScope = $rootScope.$new();
var modalElement = angular.element(template);
element.append(modalElement);
$compile(modalElement)(modalScope);
},
templateUrl: "modal.html"
};
});
Note that there are still issues. Your placing of modal into arbitrary location into a DOM may not work (not all browsers behave correctly when playing with positioning). So I would recommend creating a service that would append and render the modal just below the element.
I'm using angularJS with AngularUI API.
My problem is when I use a directive that contains collapse.
What happens:
My directive initialize correctly, but don't animate when I set collapse to false and I need the animation.
My template using directive:
<div ng-if="showDirective">
<my-form></my-form>
</div>
My directive:
angular.module('app')
.directive('myForm', MyForm);
function MyForm() {
return {
controllerAs: 'gr',
restrict: 'E',
replace: false,
templateUrl: 'myForm.html',
scope: {
cancel: '&?',
},
link:link,
controller: controller,
}
function link(scope, element, attrs, ctrl){
angular.element(document).ready(function(){
ctrl.isCollapse = false;
});
}
function controller($scope) {
var vm = this;
vm.isCollapse = true;
}
}
})()
My template of directive:
<div>
<div collapse="gr.isCollapse">
//A lot of code....
</div>
</div>
Got it!!!
I just set isCollapsed to false using $timeout:
function link(scope, element, attrs, ctrl){
$timeout(function(){
ctrl.isCollapse = false;
}, 0);
}
So collapse work after the load of directive.