I have a directive defined as follows:
app.directive('newTask', function () {
return {
restrict: 'AE',
scope: {
parentCase: "=",
options: "="
},
templateUrl: '/app/views/task/newTask.html',
controller: 'newTaskController'
};
});
This works great when I'm using it in the HTML on a page where I want to show it by default using:
<new-task parent-case="case" options="options" />
However, I'm working on having a modal pop-up and display the page similar to how the other page does it.
To do so, inside of the button click, I have
var modalInstance = $modal.open({
templateUrl: '/app/views/task/newTask.html',
backdrop: 'static',
controller: 'newTaskController',
resolve: {
parentCase: function () {
return {};
},
options: function () {
return { InitialTask: true };
}
}
})
This isn't passing 'parentCase' and 'options' through over $scope. It looks like instead it wants me add parameters to the newTaskController to allow these to come through. Is there a way to get these to resolve through the new $scope on newTaskController similar to how I do it through the HTML?
Do I need to have a separate "newTaskModal.html" that gets opened instead and just have
<new-task parent-case="case" options="options" />
on it in order to get the functionality I'm looking for?
"I think you can pass a scope parameter to your $model.open function. Try adding scope: $scope to your object" -- Komo
Related
I've recently switched all our modals directives in our app over to Angular-ui-Bootstrap modals. Much better, however running into a new style of modal which closes on mouseleave instead of a cancel click.
this.leaveTag = (tag) => {
TagHover.off();
};
this.hoverTag = (tag) => {
TagHover.display();
};
Above is the view logic that calls functions inside of our TagHover Factory.
Below is the Factory, the TagHover.display works fine like with our other modals, but what I'm trying to do with the leaveTag > TagHover.off is call the modal.close. Not working so far.
My question is how do you call the close functionality within the TagHoverController, or close on the $uibModal from my tagsPanel component -> TagsHover Factory? (Without using $scope or $rootScope events)
I'm not trying to call close/cancel from within the TagHover Ctrl scope, but trying to call close from a Parent scope.
const TagHover = angular.module('tickertags-shared')
.controller('TagHoverController', TagHoverController)
.factory('TagHover', factory);
TagHoverController.$inject = [
'TagHover'];
function TagHoverController(
TagHover) {
this.$onInit = () => {
console.log('TagHover onInit')
};
this.cancel = () => this.$close();
}
factory.$inject = ['$uibModal'];
function factory($uibModal) {
const display = () => {
const modal = $uibModal.open({
controllerAs: 'tghov',
bindToController:true,
templateUrl: 'tags/tag_hover.html',
windowClass: 'dash-modal',
resolve: {},
controller: 'TagHoverController'
});
};
const off = () => {
$uibModal.close({});
};
return {
display,
off
}
}
module.exports = TagHover;
Here are the docs https://angular-ui.github.io/bootstrap/#/modal
The open method returns a modal instance, an object with the following properties:
close(result) (Type: function) - Can be used to close a modal, passing a result.
I also logged out the $uibModal object and I only see an open function, no close :(
In your case, Your are using Factory for dynamic Modal. so you can use $uibModalStack in the below two ways.
$uibModalStack.dismissAll(); // dismiss all opened modal
$uibModalStack.dismiss(openedModal.key); // dismiss modal by key
Example of dismiss Method.
var top = $uibModalStack.getTop();
if (top) {
$uibModalStack.dismiss(top.key);
}
It's very important to do dismissing the modal during router changes since its dynamic modal.
In general, $uibModal will help to open the modal then each modal is $uibModalInstance, if you want to close modal inside the modal.
Opening Modal on Event
angular.module('myPage')
.controller('PageController', ['$uibModal',
function($uibModal) {
function onModalLink() {
$uibModal.open({
templateUrl: 'app/modals/paymentTpl.html',
controller: 'PaymentModalController as vm',
windowClass: 'generalModal myModal'
});
}
}
]);
To Close from Instance.
angular.module('paymentModal')
.controller('PaymentModalController', [
'$uibModalInstance',
function ChangeRepaymentController($uibModalInstance) {
function onCancel() {
$uibModalInstance.close(repaymentPercentage);
}
}
]);
modalInstance - The modal instance. This is the same $uibModalInstance injectable found when using controller.
WIKI Reference: https://github.com/angular-ui/bootstrap/tree/master/src/modal/docs
This is wrong approach - you can not "just close modal", cause you dont tell which modal to close. I recommend you to redesign this...
You can have a look at $uibModalStack - it stores opened modals and have methods like dismisAll
I use close() method with $uibModal and open() method for manage in AngularJS $uiModal
Open method
vm.lanzarPopShowTask = lanzarPopShowTask;
function lanzarPopShowTask(index){
vm.modalInstance = $uibModal.open({
animation: true,
ariaLabelledBy: 'modal-title-top',
ariaDescribedBy: 'modal-body-top',
templateUrl: '/btask/index/task.html',
size: 'm',
controller: function ($scope) {
vm.task = vm.tasks[index];
vm.index = index;
},
scope: $scope
});
}
And Close method
vm.modalInstance.close();
When doing this I set the modal as a scope variable then use $scope.sweetModal.close() or $scope.sweetModal.dismiss() you just have to remember that if you were to do the following it wouldn't work:
$scope.openModal = function () {
$scope.sweetModal = $uibModal.open({
templateUrl: '/modals/sweetModal.html',
size: 'md',
scope: $scope,
backdrop: true
})
.result.then($scope.modalCloseFunction, $scope.modalDismissFunction);
};
Where as the following would work because of how the variable is set:
$scope.openModal = function () {
$scope.sweetModal = $uibModal.open({
templateUrl: '/modals/sweetModal.html',
size: 'md',
scope: $scope,
backdrop: true
});
$scope.sweetModal.result.then($scope.modalCloseFunction, $scope.modalDismissFunction);
};
I have two scopes and need to combine them. Does anyone know the best way to do this? below are the two scopes. the second one comes from a service
The first scope, retrieves info from database using PHP SLIM RESTful API
Data.get('posts').then(function(data){
$scope.posts = data.data;
});
The second scope retrieves info from database via a service
dataShare.getconfigs().then(function(data){
$scope.configs = data;
});
UPDATE:
When I open the modal to edit I only get the $scope.posts. I am not currently passing through the $scope.configs
$scope.open = function (p,size) {
var modalInstance = $uibModal.open({
templateUrl: 'views/postsEdit.html',
controller: 'postsEditCtrl',
size: size,
resolve: {
item: function () {
return p;
}
}
}); ...
The problem is that $modal.open will create new isolated scope which will be used inside of modal controller and template. This new scope is going to be a direct child of the $rootScope, and thus it will not inherit from your $scope. However, what you want is to inherit from the $scope object from which you open a modal. For this configure modal like this:
$scope.open = function(p, size) {
var modalInstance = $uibModal.open({
templateUrl: 'views/postsEdit.html',
controller: 'postsEditCtrl',
size: size,
scope: $scope, // <-- use $scope as a parent to for modal scope
resolve: {
item: function() {
return p;
}
}
});
};
I am using angular ui for bootstrap for its modals:
http://angular-ui.github.io/bootstrap/#/modal
I am opening a modal with a controller and templateUrl with:
var modalInstance = $uibModal.open({
animation: true,
templateUrl: $scope.templateUrl,
controller: $scope.controller,
size: 'lg',
resolve: {
formModel: item
}
});
where formModel is the model I will use in the modal.
Here is the controller for the modal:
app.controller('commentCtrl', ['$scope', '$modalInstance', 'formModel', function ($scope, $modalInstance, formModel) {
$scope.formModel = {};
var loadFormModel = function () {
if (formModel !== undefined) {
$scope.formModel = formModel;
}
};
loadFormModel();
}]);
This modal has child directives and needs to pass properties of formModel to them
template:
<div>
<child model="formModel.Comment"></child>
</div>
but child is created before the modal's controller has loaded formModel. Inside the child I want to use model as:
app.directive('child', function () {
return {
restrict: 'E',
template: '<textarea ng-model="model"></textarea>',
link: linkFn,
controller: controllerFn,
scope: {
model: '='
}
};
});
Edit:
I've found that I can do:
<div>
<child model="formModel" property="Comment"></child>
</div>
...
app.directive('child', function () {
return {
restrict: 'E',
template: '<textarea ng-model="model[property]"></textarea>',
link: linkFn,
controller: controllerFn,
scope: {
model: '=',
property: '#'
}
};
});
Is there a better way to do this without the extra attribute?
Edit 2:
I have found where the bug is:
http://plnkr.co/edit/kUWYDvjR8YArdqtQRHhi?p=preview
See fItem.html for some reason having any ng-if causes the binding to stop working. I have put a contrived ng-if='1===1' in for demonstration
This happens because ng-if directive creates new inherited scope, so the bug is just a common scope prototypal inheritance pitfall.
The most concise way to get around it is to use controllerAs syntax in conjunction with bindToController, the avoidance of undesirable scope inheritance side effects is the most common use case for them. So it will be
app.directive('fItem', function () {
return {
restrict: 'E',
replace: true,
templateUrl: 'fItem.html',
controller: ['$scope', function ($scope) {
}],
controllerAs: 'vm',
bindToController: true,
scope: {
model: '='
}
};
});
and
<div class="input-group">
<textarea ng-if='1===1' ng-model="vm.model" class="form-control"></textarea>
</div>
Not sure what you are trying to do. If you need just to wait until variable is resolved, you need just use promise: (Here is simple one using $timeout, if you use i.e. $http - you ofc dont need $q and $timeout)
resolve: {
something: function () {
return $q(function(resolve, reject) {
setTimeout(function() {
resolve('Hello, world!');
}, 3000);
});
Then modal will be opened only after promise is resolved.
http://plnkr.co/edit/DW4MzIO4ej0JorWRgWIK?p=preview
Also keep in mind that you can wrap you object, so if in scope you have $scope.object = {smth : 'somevalue'} :
resolve: {
object: function () {
return $scope.object;
});
And in modal controller:
$scope.object = object;
Now object in initial controller scope and object in modal scope point to same javascript object, so any time you change one - another changes. You are free to use object.smth in modal template as usual property. And as soon as it will change you will see changes.
I have a directive i'm using to do the same search filtering across multiple pages. So the directive will be using a service and get pretty hefty with code. Because of that I want to link to a controller instead of have the controller inside the directive like this:
.directive('searchDirective', function($rootScope) {
return {
restrict: 'E',
templateUrl:'searchtemplate.html',
controller: 'searchCtrl',
controllerAs: 'search'
};
});
I also want access to parent scope data inside the template, so I don't want to use a isolated scope.
Anyway here's what i'm not sure how to do. My directive looks like this:
<search-directive filter="foo"/>
How do I pass in the value in the filter attribute so that I can access it in my controller using $scope.filter or this.filter?
If I were using an isolated scope it'd be simple. If i had the controller in the same page I could use $attrs. But since i'm using a controller from another spot and don't want an isolated scope i'm not sure how to get the attrs values into the controller.
Any suggestions?
What about using the link function and passing the value to the scope?
return {
restrict: 'E',
templateUrl:'searchtemplate.html',
controller: 'searchCtrl',
controllerAs: 'search',
link: function (scope, element, attr) {
scope.filter = attr.filter;
}
};
searchDirective.js
angular
.module('searchDirective', []).controller('SearchCtrl', SearchCtrl)
.directive('SearchDirective', directive);
function directive () {
var directive = {
templateUrl:'searchtemplate.html',
restrict: "E",
replace: true,
bindToController: true,
controller: 'searchCtrl as search',
link: link,
scope: { filter:'=' } // <-- like so here
};
return directive;
function link(scope, element, attrs) {}
}
SearchCtrl.$inject = [
'$scope',
'$filter'];
function SearchCtrl(
$scope,
$filter) {
/** Init SearchCtrl scope */
/** ----------------------------------------------------------------- */
var vs = $scope;
// ....
Also I highly recommend checking out this AngularJS style guide, how you are writing your directive above is how I use to do it too. John Papa shows some way better ways: https://github.com/johnpapa/angular-styleguide
Directives:
https://github.com/johnpapa/angular-styleguide#directives
Controllers:
https://github.com/johnpapa/angular-styleguide#controllers
Flip the values of bindToController and scope around.
{
....
scope: true,
bindToController: { filter:'=' }
...
}
I have just hit the same issue over the weekend, and made a simple complete example here: bindToController Not Working? Here’s the right way to use it! (Angular 1.4+)
Using Angular - UI Bootstrap
I am passing data into a modalInstance like the below. In the modal, users have the ability to create new items. On the save button press, a new item is sent to the server. I need the ability to refresh the modal instance with the updated data from $scope.items. Note, the modal doesn't close on the save, so I can't just re-open it. Any help would be greatly appreciated.
$scope.items = ['item1', 'item2', 'item3'];
$scope.open = function (size) {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function () {
// post updated $scope.items to server
// get fresh $scope.items from server
// notify modal of the updated items
}, function () {
});
};
});
You can try just to create scope for your $modalInstance as a child of current $scope like this:
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
scope: $scope
});
So now after add some item to your items everything will work fine.
For more info you can take a look at description of $modal directive on the angular bootstrap page:
scope - a scope instance to be used for the modal's content (actually the $modal service is going to create a child scope of a provided scope). Defaults to $rootScope
Demo: http://plnkr.co/edit/khzNQ0?p=preview
Hope, it will resolve your problem ;)