how to work with data from another controller in modal window? - javascript

I have a question about how can I get data from a controller and put it into a scope of another controller which is modal window...
I will explain:
here is my event, which opens dialog window (angular-strap modal):
openDialog () {
this.$modal({
show: true,
html: true,
placement: 'center',
type: 'large',
templateUrl: 'tmpl.html',
controller: myController
});
}
this is my modal window template (tmpl.html):
<div class="modal-body" id="modal-body">
<my-directive></my-directive>
</div>
as I use webpack, I initialize a module with my directive in main index.js
here is a small example of my template of a directive:
<span class="some-name">{{$ctrl.num}} </span>
here is my another controller:
constructor($scope) {
super($scope);
this.$scope = $scope;
this.num = 10;
}
So, as you can see there will be 10 in the span, I also need to get data from another controller, which stores i.e. data = ['asd', 'apple']; and so on
is there a better to do that?

If I understand your question correctly, you can pass scope from the parent controller to the modal by adding scope to your modal options. See below:
this.$modal({
show: true,
html: true,
placement: 'center',
type: 'large',
templateUrl: 'tmpl.html',
controller: myController,
scope: $scope
});
Is that all that you're asking?

You can use resolve property from modal
openDialog () {
this.$modal({
show: true,
html: true,
placement: 'center',
type: 'large',
templateUrl: 'tmpl.html',
controller: myController,
resolve : {
objData{
dataFromCtrl : $scope.dataFromAnoterCtrl// you can fetch data here either from parent scope or factory/service.
}
}
});
}
And then in myController , you can get the this data
.controller('myController',function(objData){
console.log(objData.dataFromCtrl); // you can get data from another controller in this modal controller.
})

Related

Implement common methods in two angular js controllers to open common html page

I am working on AngularJS application, in which I need to show common popup on creating an item. The popup will be same for all application, but the implementation of method of save and close will be different in each of calling controller.
Below is the code of common html page :
saveItem.html
<div class="modal-header">
<i class="fa fa-times-circle" data-dismiss="modal" aria-hidden="true" ng-click="vm.closeItem()" style="color: #061530;font-size: 25px;float: right;" role="button" tabindex="0"></i>
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" class="close" data-dismiss="modal" aria-hidden="true"
ng-click="vm.createItem()">Create another item
</button></div>
I used ngDialog to open common page. Below code is used to open the html page :
FirstController and SecondController :
ngDialog.open({
template: 'app/confirmation/saveItem.html',
scope: $scope,
showClose: false
});
What I want ?
I want different implementation of createItem() and closeItem() methods in FirstController and SecondController.
But when I implementing both methods in-
FirstController :
function closeItem() {
ngDialog.close();
}
function createdItem() {
//implemtation on FirstController
}
In SecondController
function closeItem() {
ngDialog.close();
}
function createdItem() {
//implemtation on SecondController
}
But it working in FirstController only. How can I write different implementation in both controllers?
Also is there any way to preserve previous state with ngDialog?
Add the methods to the scope that you provide for the dialog:
$scope.closeItem = function() { ngDialog.close(); }
$scope.createdItem = function() { // do whatever }
ngDialog.open({
template: 'app/confirmation/saveItem.html',
scope: $scope,
showClose: false
});
In the documentation for ngDialog, you can specify the controller you want to use for the dialog:
Controller that will be used for the dialog window if necessary. The
controller can be specified either by referring it by name or directly
inline.
ngDialog.open({
template: 'externalTemplate.html',
controller: 'SomeController' });
One way is to load different controllers for each situation:
function openFirstDialog() {
ngDialog.open({
template: 'app/confirmation/saveItem.html',
scope: $scope,
showClose: false,
controller: 'FirstController'
});
}
function openSecondDialog() {
ngDialog.open({
template: 'app/confirmation/saveItem.html',
scope: $scope,
showClose: false,
controller: 'SecondController'
});
}
Another solution would be to use a $scope variable to decide the action:
function openFirstDialog() {
$scope.firstController = true;
ngDialog.open({
template: 'app/confirmation/saveItem.html',
scope: $scope,
showClose: false
});
}
function openSecondDialog() {
$scope.firstController = false;
ngDialog.open({
template: 'app/confirmation/saveItem.html',
scope: $scope,
showClose: false
});
}
Then check the $scope variables in your dialog controller:
function closeItem() {
ngDialog.close();
}
function createdItem() {
if($scope.firstController) {
//implemtation on FirstController, go to page 1
}
else {
//implemtation on SecondController, go to page 2
}
}

Passing a variable to an angular 1.x component that is in a Angular Material Dialog

I am trying to pass an object to a component that is inside an angular material dialog.
The function I use to display the Dialog is:
ctrl.openCampaignSplitDialog = function(ev, split){
$mdDialog.show({
template: '<campaign-split-dialog split="$ctrl.split"></campaign-split-dialog>',
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose:true,
fullscreen: $scope.customFullscreen // Only for -xs, -sm breakpoints.
}).then(function(split) {
ctrl.addCampaignSplit(split);
}, function() {
$scope.status = 'You cancelled the dialog.';
});
};
This correctly opens up the dialog.
This is the code for the component:
angular
.module('app')
.component('campaignSplitDialog', {
templateUrl: 'app/components/campaignSplitDialog/campaignSplitDialog.html',
controller: campaignSplitDialogCntrlr,
bindings:{
split: '<'
}
});
/** #ngInject */
function campaignSplitDialogCntrlr($mdDialog) {
var ctrl = this;
console.log('splitter', ctrl.split);
}
The issue arrises from the fact I am not sure how to pass in the split object from the open dialog function to the component module. In the 'template' URL there I have split="$ctrl.split". I have tried multiple different ways but none worked. I have tried double brackets, plain variable name, and using the controllerAs syntax.
I have also tried passing the value in through the dialog by using the locals:{} paramter but because I do not specify a controller, since it is configured when the component is called upon, it does not appear in the component.
I'll answer the first line of your question - "I am trying to pass an object to a component that is inside an angular material dialog" - as the way you are trying to achieve it doesn't look correct.
CodePen
Markup
<div ng-controller="MyController as vm" ng-cloak="" ng-app="app">
<md-button class="md-primary md-raised" ng-click="vm.open($event)">
Custom Dialog
</md-button>
<script type="text/ng-template" id="test.html">
<md-dialog aria-label="Test">
<campaign-split split="text"></campaign-split>
</md-dialog>
</script>
</div>
JS
angular.module('app',['ngMaterial'])
.component('campaignSplit', {
template: '<div>{{$ctrl.split}}</div>',
bindings:{
split: '<'
}
})
.controller('MyController', function($scope, $mdDialog) {
this.open = function(ev) {
$scope.text = "Hello";
$mdDialog.show(
{
templateUrl: "test.html",
clickOutsideToClose: true,
scope: $scope,
preserveScope: true,
controller: function($scope) {
},
});
};
this.save = function () {
$mdDialog.cancel();
}
})
Hopefully this will point you in the right direction.
Check the property options.locals https://material.angularjs.org/HEAD/#mddialog-show-optionsorpreset
$mdDialog.show({
template: '<campaign-split-dialog split="$ctrl.split"></campaign-split-dialog>',
locals:{
split: $ctrl.split
},
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose:true,
fullscreen: $scope.customFullscreen // Only for -xs, -sm breakpoints.
})
The way you currently are doing it, is skipping the dialogs controller.
In this scenario there are three controllers.
1) state controller
2 dialog controller
3) component controller
The proper way to do this is:
ctrl.openCampaignSplitDialog = function(ev, split){
$mdDialog.show({
template: '<campaign-split-dialog split="split"></campaign-split-dialog>',
parent: angular.element(document.body),
targetEvent: ev,
locals: {split: $ctrl.split}
controller: function($scope, split){
$scope.split = split;
},
clickOutsideToClose:true,
fullscreen: $scope.customFullscreen // Only for -xs, -sm breakpoints.
}).then(function(split) {
ctrl.addCampaignSplit(split);
}, function() {
$scope.status = 'You cancelled the dialog.';
});
};
This is the code for the component:
angular
.module('app')
.component('campaignSplitDialog', {
templateUrl: 'app/components/campaignSplitDialog/campaignSplitDialog.html',
controller: campaignSplitDialogCntrlr,
bindings:{
split: '<'
}
});
/** #ngInject */
function campaignSplitDialogCntrlr($mdDialog) {
var ctrl = this;
console.log('splitter', ctrl.split);
}
So what is happening is, the variable $ctrl.split is going from the state controller to the dialog controller using locals, then in the dialog controller, you bind it to $scope, then from there you can pass the variable $scope.split to the component tag, that passes the variable to the component bindings

angularStrap: open directive from modal and pass value from the scope to the directive scope

i am using strapAngular for modal and i having problems in passing the scope to the directive. i search for answer over the internet and didn't found.
$scope.showModal = function(index) {
var scope = $scope.$new({productItem: "dddddd"});
var myModal = $modal({
templateUrl: "<div modal-view product='productItem' class='modal' tabindex='-1' role='dialog'></div>",
persist: true,
scope: scope,
show: false,
html: true,
animation: 'am-fade-and-scale',
placement: 'center'
});
myModal.$promise.then(myModal.show);
};
the directive loads but '$scope.product' is undefined.

Bind to model from child directive where model has not been resolved at compile-time

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.

Open a modal and link it to a directive in AngularJS

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

Categories

Resources