Angularjs How to communicate between two modals - javascript

What I am trying to do here is:
Type in the new language name and click "Add" button, the new language will be added into the existing object.
For example: the existing object: {"default": "English"}, When I type in "German", a new object is added like this: {"default": "English", "German": "German"}
Here is my PLUNKER.
Could someone help me on that? Thanks so much, I will appreciate!

I would prefer to use events. Just subscribe one piece on some event like:
$rootScope.$on('myEvent', function(event, info){
// do something
});
And another one will fire it:
scope.$broadcast('myEvent', info);
The system glitched when I was trying to save your plunkr or I don't have a permission so here the code:
var app = angular.module('plunker', ['ui.bootstrap']);
app.factory('Data', function(){
var data =
{
Language: ''
};
return {
setLanguage: function(language) {
data.Language = language;
}
}
})
var ModalDemoCtrl = function ($scope, $modal, $log) {
$scope.languages = {"sch": "Simple Chinese"};
$scope.$on('newLanguageAdded', function(e, lang){
$scope.languages[lang] = lang;
});
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
resolve: {
languages: function () {
return $scope.languages;
},
newLanguage: function () {
return $scope.newLanguage;
}
}
});
};
};
// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above.
var ModalInstanceCtrl = function ($scope, $modal, $modalInstance, languages, newLanguage) {
$scope.languages = languages;
$scope.ok = function () {
$modalInstance.close($scope.languages);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
$scope.openDialog = function () {
var modalInstance = $modal.open({
templateUrl: 'addNewLanguageDialog.html',
controller: AddNewLanguageCtrl,
});
}
var AddNewLanguageCtrl = function ($scope, $rootScope, $modalInstance, Data){
$scope.newValue = {text: ''};
$scope.$watch('newLanguage', function(newValue) {
if(newValue) Data.setLanguage(newValue);
});
$scope.add = function () {
alert($scope.newValue.text);
$rootScope.$broadcast('newLanguageAdded', $scope.newValue.text);
$modalInstance.close($scope.languages);
}
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
}
}
};
You can just copy this piece into plunkr instead yours.
Also change the layout:
<div class="modal-body">
<input ng-model="newValue.text">
</div>
Let me know if something doesn't work

You need to use a service, by definition singletons, and inject it in both models, adding a watch to the array in the service and updating accordingly in the scope of every model, from the values in the service.

An angular-ui way to achieve what you need would be to use these two basic methodologies found in the angular-ui documentation. See associated plunker for the answer below.
First is to use the close(result) inside the Instance Controller of the modal which updates the result promise property of the Instance Controller
Second is to use the result promise property to get the result(s) passed on to the close() method
Inside The AddNewLanguageCtrl is something like this
$scope.data = {newLanguage: ""};
$scope.add = function() {
$scope.close(data.newLanguage);
};
Inside the your addNewLanguageDialog.html script template
instead of using
<input ng-model="newLanguage">
use this
<input ng-model="data.newLanguage">
This is because whenever a modal is created, a new scope is created under the $rootScope(default) if a scope is not passed on to the options when the $modal.open() is invoked as stated in the angular-ui documentation. If you use newLanguage as the model then it won't receive any updates inside the AddNewLanguageCtrl. You can read this to get a better understanding of what I'm talking about regarding scopes
Inside the first modal ModalInstanceCtrl is something like this
$scope.newLanguages = [];
$scope.openDialog = function () {
var modalInstance = $modal.open({
templateUrl: 'addNewLanguageDialog.html',
controller: AddNewLanguageCtrl,
});
modalInstance.result.then(function(newLanguage) {
if(newLanguage)
$scope.newLanguages.push(newLanguage);
});
};
And then in your ModalDemoCtrl
$scope.languages = [];
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl
});
modalInstance.result.then(function(languages) {
$scope.languages = $scope.languages.concat(languages);
});
};

Related

Binding a Directive Controller's method to its parent $scope

I will explain what exactly I'm trying to do before explaining the issue. I have a Directive which holds a form, and I need to access that form from the parent element (where the Directive is used) when clicking on a submit button to check fi the form is valid.
To do this, I am trying to use $scope.$parent[$attrs.directiveName] = this; and then binding some methods to the the Directive such as this.isValid which will be exposed and executable in the parent.
This works fine when running locally, but when minifying and building my code (Yeoman angular-fullstack) I will get an error for aProvider being unknown which I traced back to a $scopeProvider error in the Controller.
I've had similar issues in the past, and my first thought was that I need to specifically say $inject for $scope so that the name isn't lost. But alas.....no luck.
Is something glaringly obvious that I am doing wrong?
Any help appreciated.
(function() {
'use strict';
angular
.module('myApp')
.directive('formDirective', formDirective);
function formDirective() {
var directive = {
templateUrl: 'path/to/template.html',
restrict: 'EA',
scope: {
user: '='
},
controller: controller
};
return directive;
controller.$inject = ['$scope', '$attrs', 'myService'];
function controller($scope, $attrs, myService) {
$scope.myService = myService;
// Exposes the Directive Controller on the parent Scope with name Directive's name
$scope.$parent[$attrs.directiveName] = this;
this.isValid = function() {
return $scope.myForm.$valid;
};
this.setDirty = function() {
Object.keys($scope.myForm).forEach(function(key) {
if (!key.match(/\$/)) {
$scope.myForm[key].$setDirty();
$scope.myForm[key].$setTouched();
}
});
$scope.myForm.$setDirty();
};
}
}
})();
Change the directive to a component and implement a clear interface.
Parent Container (parent.html):
<form-component some-input="importantInfo" on-update="someFunction(data)">
</form-component>
Parent controller (parent.js):
//...
$scope.importantInfo = {data: 'data...'};
$scope.someFunction = function (data) {
//do stuff with the data
}
//..
form-component.js:
angular.module('app')
.component('formComponent', {
template:'<template-etc>',
controller: Controller,
controllerAs: 'ctrl',
bindings: {
onUpdate: '&',
someInput: '<'
}
});
function Controller() {
var ctrl = this;
ctrl.someFormThing = function (value) {
ctrl.onUpdate({data: value})
}
}
So if an event in your form triggers the function ctrl.someFormThing(data). This can be passed up to the parent by calling ctrl.onUpdate().

How to pass form data to another page?

im using angularJS v 1.5.6 and want to know how to pass my form data correctly with $location.path.
Here is my code Page A:
<form>
...
<button type="submit" ng-click="submit(formData)">submit</button>
</form>
JS:
app.config(['$routeProvider', function ($routeProvider) {$routeProvider
// Home
.when("/", {
templateUrl: "A.html",
controller: "ACtrl"
})
.when("/B/", {
templateUrl: "B.html",
controller: "BCtrl"
})
//fallback url if nothing matches
.otherwise({
redirectTo: '/'
});
}]);
app.controller('ACtrl', function ( $scope, $location, $http) {
$scope.formData = {};
$scope.submit = function() {
$location.path("/B/" + $scope.formData );
};
});
//controller for B page
app.controller('BCtrl', ['$scope', '$routeParams',
function($scope,$routeParams) {
$scope.formData = $routeParams.formData;
}]);
it is a pretty simple example, but i cant figure out how to solve it :(
By clicking the submit nothing happens. If i remove the $scope from $scope.formData i get a error like: Error: formData is not defined.
The terms in formdata are available, i tested it with console.log($scope.formData) and everything is ok.
here is the link plunker: https://plnkr.co/edit/K5zwcmRRyom5HR4a5Q9o
EDIT
the only issue is now, how to handle the select object correctly in the foreach loop. Need help please
You can do it by creating a service and using setter/getter in order to transfer a variable.
For example like this: https://plnkr.co/edit/IuTXsVLU7dq3TylfnSYP?p=preview
app.service('TransferService', [function(){
var savedData,
service = {
getData: getData,
setData: setData
}
function getData(){
return savedData
}
function setData(data){
savedData = data
}
return service
}])
Don't use location.path...
You could either use a service or use localstorage (or some other browser storage mechanism [sessionStorage, indexdb].
Service Method Below
app.service("SomeService", function () {
var value = null;
this.set = function (val) {
value = val;
return this;
}
this.get = function () {
return value;
}
})
app.controller("ACtrl", function ($scope, SomeService) {
$scope.formData = {};
$scope.submit = function() {
//Assuming you've populated it with some data...
SomeService.set($scope.formData);
$location.path("/B/");
};
})
app.controller("BCtrl", function ($scope, SomeService) {
$scope.formData;
(function () {
//Check that the data is present in the SomeService service.
var dataFromACtrl = SomeService.get();
if (dataFromACtrl) {
$scope.formData = dataFromACtrl;
}
})();
})
Using localStrorage below, could be sessionStorage.
app.controller("ACtrl", function ($scope, SomeService) {
$scope.formData = {};
$scope.submit = function() {
//Assuming you've populated it with some data...
window.localStorage.setItem("form_data", JSON.stringify($scope.form_data));
$location.path("/B/");
};
})
app.controller("BCtrl", function ($scope, SomeService) {
$scope.formData;
(function () {
var dataFromACtrl = window.localStorage.getItem("form_data");
if (dataFromACtrl) {
$scope.formData = JSON.parse(dataFromACtrl);
}
})();
})
Note
Using the localStorage example you would need to do some clean-up, after doing whatever you want to do with that data in Bctrl you'd want to clear the entry in localstorage using either of the below lines of code:
window.localStorage.removeItem("form_data");
delete window.localStorage["form_data"];

Pass data from an Angular modal's controller back to the main controller

Here is the thing. I am not able to pass data from angular modal back to the controller where i need it. the codes given below.
Controller side
'use strict'
var DataMod = angular.module('Data', ["angularGrid", 'ui.bootstrap.contextMenu', 'ui.bootstrap']);
DataMod.controller('DataController', ['$scope', '$compile', '$uibModal', '$log','$rootScope', '$http', function ($scope, $compile, $uibModal,$log, $rootScope, $http, ngUtilityService) {
//user first clicks on Add button. A modal opens up. ModalInstanceCtrl is the controller used.
$scope.adduser = function () {
var modalInstance = $uibModal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl
});
//response data should be available here.
};
var ModalInstanceCtrl = function ($scope, $uibModalInstance) {
//ajax call is made is inside this controller and i get a response.
//this response is an object. i need to pass this object back to the adduser function. mentioned it above.
};
}
]);
As you can see above, there is the main controller. I have used a modal inside there which has its own controller. I make ajax call inside that modals controller and get a response back.
I want that response as a result to be available back at the adduser function so that i can work with that data. However, it seems that once the adduser function starts, it goes to the ModalInstanceCtrl and ends its execution there. It doesnt come back to the adduser function at all. I need a way to get back to the adduser function.
Can anyone let me know how to achieve this. Also how to pass the object response from ModalInstanceCtrl to the main controller inside adduser function.
It looks like you are using the Angular Bootstrap Modal, yes? First, I would set it up so that the modal controller is separated out from the main controller. Second, you are missing the promise needed to pass the response from the modal to the main controller. You can read about the return modal instance in the docs here: https://angular-ui.github.io/bootstrap/#/modal
This is the example code from the Angular Bootstrap plunkr: http://plnkr.co/edit/nGjBtMp33pFDAQ6r7Tew?p=info
angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($scope, $uibModal, $log) {
$scope.items = ['item1', 'item2', 'item3'];
$scope.animationsEnabled = true;
$scope.open = function (size) {
var modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: size,
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
$scope.toggleAnimation = function () {
$scope.animationsEnabled = !$scope.animationsEnabled;
};
});
// Please note that $uibModalInstance represents a modal window (instance) dependency.
// It is not the same as the $uibModal service used above.
angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($scope, $uibModalInstance, items) {
$scope.items = items;
$scope.selected = {
item: $scope.items[0]
};
$scope.ok = function () {
$uibModalInstance.close($scope.selected.item);
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
});

How do I get an instance of a controller that was created by AngularJS?

I have an app based on Angular which I initialize like this:
myapp.init = (function () {
'use strict';
var angularApp = angular.module('myapp', [])
.directive('homeIterationDirective', function () {
return function (scope, element, attrs) {
var isTopCard = scope.$last ? true : false;
cards.initSingleSwipe(element.get(0), function (event) {
// I want to call indexPageController.onSwiped(event) here!
}, isTopCard);
};
})
.directive('homeDirective', function () {
return function (scope, element, attrs) {
cards.initPanel(element, function (event) {
// I want to call indexPageController.onButtonPressed(event) here!
});
};
});
angularApp.factory('AjaxService', myapp.services.AjaxService);
angularApp.controller('IndexPageController', ['$scope', '$http', '$sce', 'AjaxService', myapp.pages.IndexPageController]);
}());
My controller looks like this:
myapp.pages.IndexPageController = function ($scope, $http, $sce, MyService) {
'use strict';
var somevalue = {};
this.onSwiped = function (event) {
doSomethingWith(event, somevalue);
};
this.onButtonPressed = function (event) {
doSomethingWith(event, somevalue);
};
};
In the 2 directives homeIterationDirective and homeDirective I have 2 callbacks cards.initSingleSwipe and cards.initPanel. Within these callbacks I want to call public methods of my controller but I don't have the instance available that Angular created from IndexPageController. How can I achieve this?
Use (inject) a service (and not a Controller) if you want "to call a public method" from another place, possibly from another Controller.
angularApp.controller('MyController', function ($scope, IndexPageService) {
IndexPageService.blah();
}));
Controller is intended to receive and modify a $scope (adding methods, variables..etc). The $scope can than be used inside the template (html) that use the controller itself.
If you want to call some controller code within the Angular context but in another place, then you should probably move that calling code to a service and then call the service method directly.
But if you want to call that method outside Angular context then, you can achieve that like this:
<div id="foo" ng-controller="IndexPageController">
<!-- code -->
</div>
Now, you can write something like this:
angular.element(document.getElementById("foo")).scope().blah();
I also think you should use a service for this. But if you still need to call one controller from another you can use $controller service
(function() {
var app = angular.module('myApp', ['ngRoute']);
app.config(function ($routeProvider) {
$routeProvider.when("/first", {
templateUrl: 'app/view.html',
controller: 'firstCtrl'
}).when("/second", {
templateUrl: 'app/view.html',
controller: 'secondCtrl'
})
.otherwise({
redirectTo: "/first"
});
});
app.controller('firstCtrl', function ($scope) {
$scope.name = "first Controller";
$scope.nameToUpper = function () {
return $scope.name.toUpperCase();
}
});
app.controller('secondCtrl', function ($scope, $controller) {
var newScope = $scope.$new();
$controller('firstCtrl', { $scope: newScope });
$scope.name = newScope.nameToUpper() + 'from second ctrl';
});
}())
and view is
<div>
{{name}}
</div>

Angular-ui modal issue

I'm trying to include an angular-ui modal in my web application but am having issues with getting everything set up.
The documentation indicate that you can use $modalInstance to inject the child controller into the parent controller but I don't quite understand how to go about doing so.
Here is the current code (it is straight from the modal demo from the documentation):
angular.module('myApp.controllers', []).
controller('addContent', function ($scope, $http, $modal, $log){
//modaltest
$scope.items = ['item1', 'item2', 'item3'];
$scope.addTerm = function () {
var newTerm = $modal.open({
templateUrl: 'newTermModal.jade',
controller: newTerms,
resolve: {
items: function () {
return $scope.items;
}
}
});
newTerm.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
}).
controller("newTerms",function($scope, $modalInstance, items){
$scope.items = items;
$scope.selected = {
item: $scope.items[0]
};
$scope.ok = function () {
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
When I run the app like it is now and click the button to open the modal (addTerm function) the app crashes with the error "ReferenceError: newTerms is not defined."
As I mentioned above, the angular-ui site indicates you can inject a controller with $modalInstance but I have not been able to figure out how.
a
Any help would be greatly appreciated!
EDIT
After adding the quotation marks on the pathname as suggested by Chandermani, it seems the modal is loading in the current page rather than the specified template.
I've changed the path to the following: templateUrl:
$scope.addTerm = function () {
var newTerm = $modal.open({
templateUrl: './views/partials/newTermModal.jade',
controller: 'newTerms',
resolve: {
items: function () {
return $scope.items;
}
}
});
A screenshot of the issue follows:
Any idea what could be causing this?
Well you can pass the controller as a string value. I took the default demo sample for modal and changed it to pass controller name instead of controller itself.
See my plunker http://plnkr.co/edit/jpJX4WvHw0SSYm3pAAzq?p=preview
So something like this
controller: 'newTerms',
should work.
I got the same problem, the modal loads main HTML file but not template.
My previous configuration was:
opens dialogs but dialog content is main HTML (like on your pic)
$scope.opts = {
backdrop: true,
backdropClick: true,
dialogFade: false,
keyboard: true,
templateUrl : 'app/reports/modalContent.html',
controller : 'ModalInstanceCtrl',
resolve: {}
};
works as expected
$scope.opts = {
backdrop: true,
backdropClick: true,
dialogFade: false,
keyboard: true,
templateUrl : '/app/reports/modalContent.html',
controller : 'ModalInstanceCtrl',
resolve: {}
};
Sounds like if you put wrong templateUrl, it by default uses main page HTML.
Be sure that you have right path for templateUrl
Hope it will help,
Have you tried to declare a dependency of 'ui.bootstrap' module? Like this:
angular.module('myApp.controllers', ['ui.bootstrap'])
Happened to me today, too. The templateUrl in the controller must match the id for the modal in the html file.
You need to define the newTerms controller before your other controller. Or you can change the code and just create a function inside your main controller with the name newTerms and remove the quotation marks for the name of your controller in your modal.
$scope.addTerm = function () {
var newTerm = $modal.open({
templateUrl: './views/partials/newTermModal.jade',
controller: newTerms,
resolve: {
items: function () {
return $scope.items;
}
}
});
var newTerms = function($scope, $modalInstance, items){
$scope.items = items;
$scope.selected = {
item: $scope.items[0]
};
$scope.ok = function () {
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
}

Categories

Resources