I have a directive that shows modal window after loading data:
.directive('nwAssets', function () {
return {
restrict: 'A',
templateUrl: 'app/dashboard/templates/nw-assets.html',
controller: controller,
scope: {
assets: '=nwAssets'
}
};
function controller($scope, $ionicModal, NwPath) {
$scope.pathToThumb = NwPath.toThumb;
$scope.pathToSrc = NwPath.toSrc;
$scope.fileName = NwPath.fileName;
$ionicModal.fromTemplateUrl('app/dashboard/templates/nw-modal.html', {
scope: $scope,
animation: 'slide-in-down'
}).then(function (modal) {
$scope.modal = modal;
});
$scope.openModal = function (src, fileName) {
$scope.pathToSrc = src;
$scope.fileName = fileName;
$scope.modal.show();
};
$scope.closeModal = function () {
$scope.modal.hide();
};
}
});
Factory I used:
.factory('NwPath', function (baseUrl) {
return {
toThumb: toThumb,
toSrc: toSrc,
fileName: fileName
};
function toThumb(asset) {
return baseUrl + '/uploads/file/' + asset.guid + '/' + assetThumbFileName(asset);
}
function toSrc(asset) {
return baseUrl + '/uploads/file/' + asset.guid + '/' + asset.file_name;
}
function assetThumbFileName(asset) {
var fileNames = asset.file_name.split('.');
fileNames[0] = fileNames[0] + '_pi_200x200';
return fileNames.join('.');
}
function fileName (asset) {
return asset.file_name;
}
});
Template where I call modal:
<div ng-repeat="asset in assets">
<img ng-if="asset.mime_type.indexOf('image') === 0"
ng-src="{{pathToThumb(asset)}}"
ng-click="openModal(pathToSrc(asset), fileName(asset))"
alt="" />
Template where modal closes:
<ion-modal-view>
<ion-header-bar class="bar bar-header bar-positive">
<h1 class="title">{{fileName}}</h1>
<div class="buttons">
<button class="button button-clear" ng-click="closeModal()">Close</button>
</div>
</ion-header-bar>
<ion-content class="text-center">
<img ng-src="{{pathToSrc}}" alt="" />
</ion-content>
It works just once: modal opens, abd data shows. But after modal is closed, it won't be shown next time and shows an error: "v6.pathToSrc is not a function"
Please help )
Related
I want to control the display of elements using a variable that is defined in the controller.
But if variables change async, my code doesn't work as expected.
In my example, I output to console value of vm.fruit inside methods setFruit and hasFruit.
And after set value for vm.fruit in setFruit, in hasFruit vm.fruit value is undefined.
Have ideas about how to fix it?
And I don't want call controllers method inside directive.
UPD. I removed the definition exampleController from asyncChoice, how suggested #LeroyStav. I think he is right. But this not solved the problem.
angular.module('app', [])
.controller('exampleController', exampleController)
.directive('wrapper', wrapper)
.directive('asyncChoice', asyncChoice);
function exampleController() {
var vm = this;
vm.selectMode = false;
vm.fruit = undefined;
vm.hasFruit = hasFruit;
vm.selectFruit = selectFruit;
vm.setFruit = setFruit;
function hasFruit() {
console.log('hasFruit: ' + vm.fruit);
return (typeof vm.fruit !== 'undefined');
}
function selectFruit() {
vm.selectMode = true;
}
function setFruit(fruit) {
setTimeout(
function() {
vm.fruit = fruit;
vm.selectMode = false;
console.log(vm.fruit);
},
1000
);
}
}
function wrapper() {
return {
restrict: 'E',
trancslude: true,
controller: 'exampleController',
controllerAs: 'vm'
};
}
function asyncChoice() {
return {
template: `
<button ng-click="selectFruit({fruit: '🍊'})">🍊</button>
<button ng-click="selectFruit({fruit: '🍋'})">🍋</button>
`,
scope: {
selectFruit: '&'
},
controller: 'exampleController',
controllerAs: 'vm'
}
}
angular.bootstrap(
document.getElementById('root'), ['app']
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div id="root">
<wrapper>
<button ng-if="!vm.hasFruit()" ng-click="vm.selectFruit()">Choice fruit</button>
<p ng-if="vm.hasFruit()">You choice <span ng-bind="vm.fruit"></span></p>
<async-choice ng-if="vm.selectMode" select-fruit="vm.setFruit(fruit)"></async-choice>
</wrapper>
</div>
I provide $scope to exampleController and call $scope.$digest() after execution async operation.
angular.module('app', [])
.controller('exampleController', exampleController)
.directive('wrapper', wrapper)
.directive('asyncChoice', asyncChoice);
exampleController.$inject = ['$scope'];
function exampleController($scope) {
var vm = this;
vm.selectMode = false;
vm.fruit = undefined;
vm.hasFruit = hasFruit;
vm.selectFruit = selectFruit;
vm.setFruit = setFruit;
function hasFruit() {
console.log('hasFruit: ' + vm.fruit);
return (typeof vm.fruit !== 'undefined');
}
function selectFruit() {
vm.selectMode = true;
}
function setFruit(fruit) {
setTimeout(
function() {
vm.fruit = fruit;
vm.selectMode = false;
console.log(vm.fruit);
$scope.$digest();
},
1000
);
}
}
function wrapper() {
return {
restrict: 'E',
trancslude: true,
controller: 'exampleController',
controllerAs: 'vm'
};
}
function asyncChoice() {
return {
template: `
<button ng-click="selectFruit({fruit: '🍊'})">🍊</button>
<button ng-click="selectFruit({fruit: '🍋'})">🍋</button>
`,
scope: {
selectFruit: '&'
},
controller: 'exampleController',
controllerAs: 'vm'
}
}
angular.bootstrap(
document.getElementById('root'), ['app']
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div id="root">
<wrapper>
<button ng-if="!vm.hasFruit()" ng-click="vm.selectFruit()">Choice fruit</button>
<p ng-if="vm.hasFruit()">You choice <span ng-bind="vm.fruit"></span></p>
<async-choice ng-if="vm.selectMode" select-fruit="vm.setFruit(fruit)"></async-choice>
</wrapper>
</div>
I'm working on a hybrid Ionic1 app and I am not able to call a controller method from inside a directive.
The problem is that inside the directive I'm able to pass controller's variables (such as variable apps) but I am not able to call removeCredentials() inside card-app directive.
I've tried so many ways to make it work but none of them solved the problem. I've also tried using the & to bind the controller method inside the directive but clicking on the X icon in the directive template triggers nothing.
Right now the code looks like this:
Controller AppsCtrl in apps.js
angular.module('testprofile')
.controller('AppsCtrl', function($scope, $state, $log, $ionicHistory, $filter, $ionicPopup, UserData, CredentialStoreService, ionicMaterialMotion, ionicMaterialInk, Auth, Effects, CredentialStoreService, Globals, Validations) {
$scope.onlyMyApps = true;
$scope.showNoItems = false;
var translate = $filter('translate');
$scope.apps = [];
$scope.mapAppsFromCredentials = function(credentials) {
var map = credentials.map(function(cred) {
/* app: "App 1"
appId: 7
profile: "Default Profile"
profileId: 0
*/
var app = UserData.getLocalApp(cred.app);
if (!app) {
$log.debug("apps.js::mapAppsFromCredentials - no local app matching credentials: "+JSON.stringify(cred));
return null;
}
var curHelper = UserData.getCurrentAppHelper(app);
return {
used: Boolean(cred.used),
id: app.id,
title: app.nameApp,
profile: cred.profile,
desc: curHelper ? curHelper.name : 'NO HELPER'
};
})
return map;
}
$scope.refresh = function() {
$log.debug("apps.js::AppsCtrl - REQUEST CREDENTIAL LIST...");
CredentialStoreService.getCredentialList(
//ON SUCCESS
function(response) {
$log.debug("apps.js::AppsCtrl - ...CREDENTIAL LIST RESPONSE: " + JSON.stringify(response));
$scope.apps = $scope.mapAppsFromCredentials(response);
Effects.init();
$scope.showNoItems = true;
for (var i = 0; i < $scope.apps.length; i++) {
if ($scope.apps[i].used) {
$scope.showNoItems = false;
break;
}
}
},
//ON ERROR
function() {
$log.debug("apps.js::AppsCtrl - ...CREDENTIAL LIST ERROR");
}
)
}
$scope.$on("$ionicView.enter", function () {
$log.debug("apps.js::$ionicView.enter - ENTER");
$scope.refresh();
});
//REMOVE CREDENTIALS
$scope.removeCredentials = function() {
$log.debug("app-details.js::removeCredential CONFIRMATION...");
$ionicPopup.confirm({
title: translate('Remove Credentials'),
template: translate('Are you sure you want to delete current credentials') + ' ' + app.nameApp + '?',
cancelText: translate('No'), // String (default: 'Cancel'). The text of the Cancel button.
//cancelType: '', // String (default: 'button-default'). The type of the Cancel button.
okText: translate('Yes'), // String (default: 'OK'). The text of the OK button.
okType: 'button-energized-900' // String (default: 'button-positive'). The type of the OK button.
}).then(function(res) {
if(res) {
$log.debug("app-details.js::removeCredential CONFIRMED!");
Auth.askPIN(true)
.then( function() {
CredentialStoreService
.removeCredential(
//authenticationProfileName
UserData.getAuthProfile(app).name,
//appProfileName
app.name,
// ON SUCCESS
onRemovedCredential,
// ON ERROR
Globals.onError);
});
} else {
$log.debug("app-details.js::removeCredential REJECTED.");
}
});
};
var onRemovedCredential = function() {
$log.debug("app-details.js::removeCredential CREDENTIALS REMOVED!");
Effects.showToast(translate('CREDENTIALS REMOVED')+'.');
$ionicHistory.nextViewOptions({
disableBack: true
});
$state.go('menu.apps', {}, {reload:true});
};
})
Directives in inclusions.js
angular.module('testprofile')
.directive('cardProfile', function() {
return {
scope: {
data:"=cardSource"
},
restrict: 'E',
templateUrl: 'app/templates/card-profile.html'
};
})
.directive('cardApp', function() {
return {
scope: {
data:"=cardSource",
},
restrict: 'E',
templateUrl: 'app/templates/card-app.html',
controller: 'AppsCtrl',
controllerAs: "ac",
bindToController: true,
link: function(scope, element, attrs, ctrl) {
scope.removeCredentials = function() {
return scope.ac.removeCredentials();
};
}
};
})
.directive('pinRequired', function(Auth) {
return {
restrict: 'A',
link: function(scope, element, attrs, ctrl) {
attrs.authorized = false;
element.on('click', function(e){
// console.log("\t\t + attrs.authorized:"+attrs.authorized);
if (attrs.authorized) {
if (attrs.href) location.href = attrs.href;
return true;
} else {
e.preventDefault();
e.stopPropagation();
Auth.askPIN(true)
.then(function() {
// console.log("inclusions.js::pinRequired - askPin - AUTHORIZED");
//THE PIN IS CORRECT!
attrs.authorized = true;
element.triggerHandler('click');
attrs.authorized = false;
});
}
});
}
};
})
;
apps.html
<ion-view view-title="Apps">
<ion-content padding="true" class="has-header bg-stable">
<h4 class="list-title"><i class="material-icons"></i> {{ 'App List' | translate }}
<!--label class="toggle toggle-calm pull-right toggle-small">
<span class="toggle-label" translate>My Apps</span>
<input type="checkbox" ng-model="onlyMyApps">
<div class="track">
<div class="handle"></div>
</div>
</label-->
</h4>
<ion-list class="">
<card-app ng-repeat="app in apps | filter:(onlyMyApps || '') && {used: true}"
card-source="app"
class="{{app.used ? 'used' : 'unused'}}"></card-app>
<div class="item padding" ng-show="showNoItems"><p class="text-center">{{ 'No saved credentials' | translate}}</span>.</p>
</div>
</ion-list>
</ion-content>
</ion-view>
card-app.html
<ion-item
menu-close=""
class="card item-thumbnail-left item-icon-right app-item">
<!--<img ng-src="{{data.thumb}}">-->
<span style="line-height:70px;vertical-align:middle" class="item-image avatar-initials h2">{{data.title|initials}}</span>
<div class="item">
<h2 class="inline-block">
<span ng-bind="data.title"></span>
</h2>
<span class="icon-right material-icons" ng-click='removeCredentials()'></span>
<div>
<span>{{'Active helper' | translate}}</span>
<h3>{{ data.desc | translate }}</h3>
</div>
</div>
</ion-item>
Solution: at the end the click event was not triggered because I had to add pointer-events: auto; and cursor: pointer; in my css
If your directive needs to call just a single function from a parent controller, just pass it as parameter (like you tried).
First ensure that controller scope is available for directive. For example create simple method and call it before directive:
// to ensure scope is ok
<button ng-click="alertMethod()"></button>
<card-app ng-repeat='' card-source='' class='' my-method="alertMethod()"></card-app>
// directive
//
scope: {
myMethod: '&'
},
template: "<button ng-click='myMethod()'>Click</button>"
That should work, but if your controller scope is not available maybe you need to use named controllers:
https://docs.angularjs.org/api/ng/directive/ngController
Using controller as makes it obvious which controller you are accessing in the template when multiple controllers apply to an element.
Than in your code:
// controller
this.alertMethod = function() {
alert('Hello');
}
// view
<div ng-app="myApp" ng-controller="testCtrl as ctrl">
<card-app ng-repeat='' card-source='' class='' my-method="ctrl.alertMethod()"></card-app>
I have declared two HTML pages in my index: Home.html and jargon.html.
Each page has its own controller loaded in the application module.
angular.module('starter', ['ionic', 'ngRoute', 'starter.homeController', 'starter.jargonController'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'templates/home.html',
controller: 'homeCtrl'
})
.state('jargon', {
url: 'jargon',
templateUrl: 'templates/jargon.html',
controller: 'jargonCtrl'
});
$urlRouterProvider.otherwise('/home');
});
My problem is that jargon.html has two other controllers:
<ion-view title="Jargon">
<ion-content>
<a class="item" href="#/jargon"></a>
<ion-pane ng-controller="CardsCtrl">
<div class="testimage">
<img ng-src="img/Logo.png" class="logo">
</div>
<swipe-cards on-card-swipe="onSwipe($event)">
<swipe-cards>
<swipe-card on-card-swipe="cardSwiped()" id="start-card">
</swipe-card>
<swipe-card ng-repeat="card in cards" on-destroy="cardDestroyed($index)" on-card-swipe="cardSwiped($index)">
<div ng-controller="CardCtrl">
<div class="image">
<img ng-src="{{card.image}}">
</div>
<div class="title">
{{card.Description}}
</div>
</div>
</swipe-card>
</swipe-cards>
</ion-pane>
</ion-content>
Controllers to manipulate the cards:
.controller('CardsCtrl', function($scope, $ionicSwipeCardDelegate) {
var cardTypes = [
{ image: 'img/cards/ASE card.png' },
{ image: 'img/cards/MCR-card.png' },
{ image: 'img/cards/R2A card.png' },
{ image: 'img/cards/RRH card.png' }];
$scope.cards = Array.prototype.slice.call(cardTypes, 0, 0);
//intialisation premiere carte
var newCard = cardTypes[0];
newCard.id = Math.random();
$scope.cards.push(angular.extend({}, newCard));
$scope.cardSwiped = function(index) {
$scope.addCard();
};
$scope.cardDestroyed = function(index) {
$scope.cards.splice(index, 1);
};
$scope.addCard = function() {
var newCard = cardTypes[Math.floor(Math.random() * cardTypes.length)];
newCard.id = Math.random();
$scope.cards.push(angular.extend({}, newCard));
}
})
.controller('CardCtrl', function($scope, $ionicSwipeCardDelegate) {
$scope.goAway = function() {
var card = $ionicSwipeCardDelegate.getSwipeableCard($scope);
card.swipe();
};
});
My question is: Where can I call both CardsCtrl and CardCtrl ? In the same jargonController.js file?
Here is a simple example:
<div ng-controller="HelloCtrl">
<p>{{fromService}}</p>
</div>
<br />
<div ng-controller="GoodbyeCtrl">
<p>{{fromService}}</p>
</div>
JavaScript:
//angular.js example for factory vs service
var app = angular.module('myApp', []);
app.service('testService', function(){
this.sayHello= function(text){
return "Service says \"Hello " + text + "\"";
};
this.sayGoodbye = function(text){
return "Service says \"Goodbye " + text + "\"";
};
});
function HelloCtrl($scope, testService)
{
$scope.fromService = testService.sayHello("World");
}
function GoodbyeCtrl($scope, testService)
{
$scope.fromService = testService.sayGoodbye("World");
}
http://jsfiddle.net/Ne5P8/2701/
I'm having an issue with Angular Material where my forms/inputs and buttons don't show up.
I'm guessing it's because I havent added ngMaterial as a dependency. When I do, it breaks my code.
this is my original app.js file:
angular.module('myApp', ['ngRoute',])
.config( [
'$compileProvider',
function( $compileProvider ) {
var currentImgSrcSanitizationWhitelist = $compileProvider.imgSrcSanitizationWhitelist();
var newImgSrcSanitizationWhiteList = currentImgSrcSanitizationWhitelist.toString().slice(0,-1)
+ '|chrome-extension:'
+currentImgSrcSanitizationWhitelist.toString().slice(-1);
console.log("Changing imgSrcSanitizationWhiteList from "+currentImgSrcSanitizationWhitelist+" to "+newImgSrcSanitizationWhiteList);
$compileProvider.imgSrcSanitizationWhitelist(newImgSrcSanitizationWhiteList);
}
])
.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'templates/home.html',
controller: 'MainCtrl'
})
.when('/settings', {
templateUrl: 'templates/settings.html',
controller: 'SettingsCtrl'
})
.otherwise({redirectTo: '/'});
})
.provider("Weather", function () {
var apiKey = "";
this.setApiKey = function (key) {
if (key) {
this.apiKey = key;
}
};
this.getUrl = function (type, ext) {
return "http://api.wunderground.com/api/" + this.apiKey + "/" + type +
"/q/" + ext + ".json";
};
this.$get = function ($q, $http) {
var self = this;
return {
getWeatherForecast: function (city) {
var d = $q.defer();
$http({
method: "GET",
url: self.getUrl("forecast", city),
cache: true
}).success(function (data) {
// forecasts are nested inside forecast.simpleforecast
// console.log(data);
d.resolve(data.forecast.simpleforecast);
}).error(function (error) {
d.reject(error);
});
return d.promise;
}
};
};
})
.config(function(WeatherProvider) {
WeatherProvider.setApiKey('7b78fc434225f02f');
})
.controller('MainCtrl',
function($scope, $timeout, Weather){
//build date object
$scope.date = {};
// Update function
var updateTime = function() {
$scope.date.raw = new Date();
$timeout(updateTime, 1000);
}
// Kick off the update function
updateTime();
$scope.weather = {};
Weather.getWeatherForecast("IL/Chicago")
.then(function (data) {
$scope.weather.forecast = data;
});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!doctype html>
<html data-ng-app="myApp" data-ng-csp="">
<head>
<meta charset="UTF-8">
<title>Weathim</title>
<link rel="stylesheet" href="css/angular-material.min.css">
<link rel="stylesheet" href="css/main.css">
<link rel="stylesheet" href="themes/teal-theme.css">
<link href='http://fonts.googleapis.com/css?family=Rajdhani|Dosis:400,700|Raleway:400,100,300|Advent+Pro' rel='stylesheet' type='text/css'>
</head>
<body ng-controller="MainCtrl" md-theme="teal">
<md-toolbar flex="100" flex-order="1">
<div class="md-toolbar-tools">
<h2>
<span>{{ date.raw | date:'EEEE MMMM yyyy' }}</span>
</h2>
<span flex></span>
<md-button class="md-icon-button" aria-label="Settings">
<md-icon><img src="imgs/settings.png"></md-icon>
</md-button>
</div>
</md-toolbar>
<div class="container">
<md-content layout="row" layout-align="center">
<div id="datetime">
<div class="time">{{ date.raw | date:'hh:mm' }}</div><div class="sec">{{ date.raw | date:'ss' }}</div>
<div class="day"></div>
</div>
</md-content>
<div layout="row" layout-sm="column">
<md-content class="bg1" ng-repeat="day in weather.forecast.forecastday" id="forecast">
<div ng-class="{today: $index == 0}">
<div flex="25">
<md-toolbar class="md-warn">
<div class="md-toolbar-tools" layout-align="center">
<h2 class="md-flex" ng-if="$index == 0">Now</h2>
<h2 class="md-flex" ng-if="$index != 0">{{ day.date.weekday }}</h2>
</div>
</md-toolbar>
<div class="infocontent" layout layout-align="center">
<img class="{{ day.icon }}" ng-src="imgs/{{ day.icon }}.png"/>
</div>
<div layout="row">
<div flex class="low">
Low: <span class="temp" layout layout-align="center">{{ day.low.fahrenheit }}</span>
</div>
<div flex class="high">
High: <span class="temp" layout layout-align="center">{{ day.high.fahrenheit }}</span>
</div>
</div>
<md-toolbar class="md-warn border">
<div class="md-toolbar-tools" layout-align="center">
<h2 class="md-flex">{{ day.conditions }}</h2>
</div>
</md-toolbar>
</div>
</div>
</md-content>
</div>
<md-content md-theme="docs-dark" layout-padding layout="row" layout-sm="column">
<input ng-model="" placeholder="Placeholder text"><md-button class="md-raised md-primary">Primary</md-button>
</md-content>
</div>
<script src="./js/vendor/angular.min.js"></script>
<script src="./js/vendor/angular-route.min.js"></script>
<script src="./js/vendor/angular-material.min.js"></script>
<script src="./js/vendor/angular-animate.min.js"></script>
<script src="./js/app.js"></script>
</body>
</html>
i attempted to add multiple dependencies but it just broke my code:
angular.module('myApp', [
'ngRoute',
'ngMaterial'
]).config(function($mdThemingProvider) {
$mdThemingProvider.theme('teal')
.primaryPalette('teal')
.accentPalette('orange');
})
.config( [
'$compileProvider',
function( $compileProvider ) {
var currentImgSrcSanitizationWhitelist = $compileProvider.imgSrcSanitizationWhitelist();
var newImgSrcSanitizationWhiteList = currentImgSrcSanitizationWhitelist.toString().slice(0,-1)
+ '|chrome-extension:'
+currentImgSrcSanitizationWhitelist.toString().slice(-1);
console.log("Changing imgSrcSanitizationWhiteList from "+currentImgSrcSanitizationWhitelist+" to "+newImgSrcSanitizationWhiteList);
$compileProvider.imgSrcSanitizationWhitelist(newImgSrcSanitizationWhiteList);
}
])
.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'templates/home.html',
controller: 'MainCtrl'
})
.when('/settings', {
templateUrl: 'templates/settings.html',
controller: 'SettingsCtrl'
})
.otherwise({redirectTo: '/'});
})
.provider("Weather", function () {
var apiKey = "";
this.setApiKey = function (key) {
if (key) {
this.apiKey = key;
}
};
this.getUrl = function (type, ext) {
return "http://api.wunderground.com/api/" + this.apiKey + "/" + type +
"/q/" + ext + ".json";
};
this.$get = function ($q, $http) {
var self = this;
return {
getWeatherForecast: function (city) {
var d = $q.defer();
$http({
method: "GET",
url: self.getUrl("forecast", city),
cache: true
}).success(function (data) {
// forecasts are nested inside forecast.simpleforecast
// console.log(data);
d.resolve(data.forecast.simpleforecast);
}).error(function (error) {
d.reject(error);
});
return d.promise;
}
};
};
})
.config(function(WeatherProvider) {
WeatherProvider.setApiKey('7b78fc434225f02f');
})
.controller('MainCtrl',
function($scope, $timeout, Weather){
//build date object
$scope.date = {};
// Update function
var updateTime = function() {
$scope.date.raw = new Date();
$timeout(updateTime, 1000);
}
// Kick off the update function
updateTime();
$scope.weather = {};
Weather.getWeatherForecast("IL/Chicago")
.then(function (data) {
$scope.weather.forecast = data;
});
});
any help would be appreciated
I've created an application in angular js for add and remove popup model, The popup model is coming
but on saving i'm getting undefined and cancel is not working .
JSFIDDLE
can anyone please tell me some solution for this
var app = angular.module('mainApp', ['commonApp', 'ui.bootstrap']);
app.controller('mainController', function ($scope, $rootScope, $modal, $log) {
$scope.users = [{
userId: 1,
userName: "Jhonny"
}, {
userId: 2,
userName: "Sunny"
}];
$scope.selectedUsers = {
users: []
};
$scope.open = function (users, dept) {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'mainController',
resolve: {
usersInModalScope: function () {
return users;
},
deptInModalScope: function () {
return dept;
}
}
});
};
});
var commonApp = angular.module('commonApp', ['ui.bootstrap']);
commonApp.controller('ModalInstanceCtrl', function ($scope, $rootScope) {
$scope.cancel = function () {
$scope.modalInstance.close();
if ($rootScope.$root.$$phase != '$apply' && $rootScope.$root.$$phase != '$digest') {
$rootScope.$apply();
}
}
$scope.save = function () {
alert(JSON.stringify($scope.selectedUsers));
}
});
commonApp.directive('multiSelect', function ($q) {
return {
restrict: 'E',
controller: "ModalInstanceCtrl",
require: 'ngModel',
scope: {
selectedLabel: "#",
availableLabel: "#",
displayAttr: "#",
available: "=",
model: "=ngModel",
eventHandler: '&ngClick'
},
template: '<div class="multiSelect">' +
'<div class="select">' +
'<label class="control-label" for="multiSelectAvailable">{{ availableLabel }} ' +
'({{ available.length }})</label>' +
'<select id="multiSelectAvailable" ng-model="selected.available" multiple ' +
'ng-options="e as e[displayAttr] for e in available"></select>' +
'</div>' +
'<div class="select buttons">' +
'<button class="btn mover right" ng-click="add()" title="Add selected" ' +
'ng-disabled="selected.available.length == 0">' +
'<i class=" icon-arrow-right"></i>' +
'</button>' +
'<button class="btn mover left" ng-click="remove()" title="Remove selected" ' +
'ng-disabled="selected.current.length == 0">' +
'<i class="icon-arrow-left"></i>' +
'</button>' +
'</div>' +
'<div class="select">' +
'<label class="control-label" for="multiSelectSelected">{{ selectedLabel }} ' +
'({{ model.length }})</label>' +
'<select id="currentRoles" ng-model="selected.current" multiple ' +
'class="pull-left" ng-options="e as e[displayAttr] for e in model">' +
'</select>' +
'</div>' +
'</div>' +
'<div class="wrapper text-center">' +
'<button class="btn btn-default" ng-click="save()"> Save </button>' +
'<button class="btn btn-default" ng-click="cancel()">Cancel</button>' +
'</div>',
link: function (scope, elm, attrs) {
scope.selected = {
available: [],
current: []
};
var dataLoading = function (scopeAttr) {
var loading = $q.defer();
if (scope[scopeAttr]) {
loading.resolve(scope[scopeAttr]);
} else {
scope.$watch(scopeAttr, function (newValue, oldValue) {
if (newValue !== undefined) loading.resolve(newValue);
});
}
return loading.promise;
};
var filterOut = function (original, toFilter) {
var filtered = [];
angular.forEach(original, function (entity) {
var match = false;
for (var i = 0; i < toFilter.length; i++) {
if (toFilter[i][attrs.displayAttr] == entity[attrs.displayAttr]) {
match = true;
break;
}
}
if (!match) {
filtered.push(entity);
}
});
return filtered;
};
scope.refreshAvailable = function () {
scope.available = filterOut(scope.available, scope.model);
scope.selected.available = [];
scope.selected.current = [];
};
scope.add = function () {
scope.model = scope.model.concat(scope.selected.available);
scope.refreshAvailable();
};
scope.remove = function () {
scope.available = scope.available.concat(scope.selected.current);
scope.model = filterOut(scope.model, scope.selected.current);
scope.refreshAvailable();
};
$q.all([dataLoading("model"), dataLoading("available")]).then(function (results) {
scope.refreshAvailable();
});
}
};
})
Here
Working Demo $rootScope
Working Demo Factory Version
Problem with controller's scope.mainController and ModalInstanceCtrl have their own scope. it is not same scope instance totally different so here $rootScope is same instance across app.
First working demo I'm using $rootScope variable. Depending on global object really bad design.
To communicate between controllers you need to create factory service like userFactory then pass around your controllers. In factory service keep your modal.
var app = angular.module('mainApp', ['commonApp', 'ui.bootstrap']);
app.controller('mainController', function ($scope, $rootScope, $modal, $log, userFactory) {
$scope.users = userFactory.users;
$scope.selectedUsers = userFactory.selectedUsers;
$scope.open = function (users, dept) {
userFactory.modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'mainController',
resolve: {
usersInModalScope: function () {
return userFactory.users;
},
deptInModalScope: function () {
return userFactory.dept;
}
}
});
};
});
app.factory('userFactory', function (){
return {
modalInstance:{},
users : [{
userId: 1,
userName: "Jhonny"
},
{
userId: 2,
userName: "Sunny"
}
],
selectedUsers :{users: []},
dept : [],
}
});
var commonApp = angular.module('commonApp', ['ui.bootstrap']);
commonApp.controller('ModalInstanceCtrl', function ($scope, $rootScope, userFactory) {
$scope.cancel = function () {
userFactory.modalInstance.close();
if ($rootScope.$root.$$phase != '$apply' && $rootScope.$root.$$phase != '$digest') {
$rootScope.$apply();
}
}
$scope.save = function () {
alert(JSON.stringify(userFactory.selectedUsers));
}
});
commonApp.directive('multiSelect', function ($q) {
return {
restrict: 'E',
controller: "ModalInstanceCtrl",
require: 'ngModel',
scope: {
selectedLabel: "#",
availableLabel: "#",
displayAttr: "#",
available: "=",
model: "=ngModel",
eventHandler: '&ngClick'
},
template: '<div class="multiSelect">' +
'<div class="select">' +
'<label class="control-label" for="multiSelectAvailable">{{ availableLabel }} ' +
'({{ available.length }})</label>' +
'<select id="multiSelectAvailable" ng-model="selected.available" multiple ' +
'ng-options="e as e[displayAttr] for e in available"></select>' +
'</div>' +
'<div class="select buttons">' +
'<button class="btn mover right" ng-click="add()" title="Add selected" ' +
'ng-disabled="selected.available.length == 0">' +
'<i class=" icon-arrow-right"></i>' +
'</button>' +
'<button class="btn mover left" ng-click="remove()" title="Remove selected" ' +
'ng-disabled="selected.current.length == 0">' +
'<i class="icon-arrow-left"></i>' +
'</button>' +
'</div>' +
'<div class="select">' +
'<label class="control-label" for="multiSelectSelected">{{ selectedLabel }} ' +
'({{ model.length }})</label>' +
'<select id="currentRoles" ng-model="selected.current" multiple ' +
'class="pull-left" ng-options="e as e[displayAttr] for e in model">' +
'</select>' +
'</div>' +
'</div>' +
'<div class="wrapper text-center">' +
'<button class="btn btn-default" ng-click="save()"> Save </button>' +
'<button class="btn btn-default" ng-click="cancel()">Cancel</button>' +
'</div>',
link: function (scope, elm, attrs) {
scope.selected = {
available: [],
current: []
};
var dataLoading = function (scopeAttr) {
var loading = $q.defer();
if (scope[scopeAttr]) {
loading.resolve(scope[scopeAttr]);
} else {
scope.$watch(scopeAttr, function (newValue, oldValue) {
if (newValue !== undefined) loading.resolve(newValue);
});
}
return loading.promise;
};
var filterOut = function (original, toFilter) {
var filtered = [];
angular.forEach(original, function (entity) {
var match = false;
for (var i = 0; i < toFilter.length; i++) {
if (toFilter[i][attrs.displayAttr] == entity[attrs.displayAttr]) {
match = true;
break;
}
}
if (!match) {
filtered.push(entity);
}
});
return filtered;
};
scope.refreshAvailable = function () {
scope.available = filterOut(scope.available, scope.model);
scope.selected.available = [];
scope.selected.current = [];
};
scope.add = function () {
scope.model = scope.model.concat(scope.selected.available);
scope.refreshAvailable();
};
scope.remove = function () {
scope.available = scope.available.concat(scope.selected.current);
scope.model = filterOut(scope.model, scope.selected.current);
scope.refreshAvailable();
};
$q.all([dataLoading("model"), dataLoading("available")]).then(function (results) {
scope.refreshAvailable();
});
}
};
})
I am pretty sure you need to reference the modalInstanceController when you create the modal and not the mainController.
$scope.open = function (users, dept) {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
resolve: {
usersInModalScope: function () {
return users;
},
deptInModalScope: function () {
return dept;
}
}
});
};
And you need to pass you resolutions into the parameters of the controller as well, also the $modalInstance service is where the methods close, dismiss, etc live...
commonApp.controller('ModalInstanceCtrl', function ($scope, $rootScope, $modalInstance, usersInModalScope, deptInModalScope) {
$scope.cancel = function () {
$modalInstance.close();
}
$scope.save = function () {
alert(JSON.stringify($scope.selectedUsers));
}
});
Now having said this I couldnt get your implementation to work the way you want it. But in our implementation of the ui.bootstrap and the modals we use this version.
ProductsCtrl
angular.module('app', ['ui.bootstrap'])
.controller('AppController', function($scope, $modal, $templateCache) {
$scope.product = { product: 'I am the product' };
$scope.openEditProductModal = function () {
var editProductModal = $modal.open({
templateUrl: 'edit-product.html',
controller: 'EditProductModalController',
resolve: {
product: function () {
return $scope.product;
}
}
});
editProductModal.result.then(function (product) {
$scope.product = product;
});
};
})
Modal Controller
.controller('EditProductModalController', function ($scope, $modalInstance, product) {
$scope.product = product;
$scope.ok = function () {
/**
* Set the edited description and close the modal resolving the promise
*/
$scope.product = product
$modalInstance.close($scope.product);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
})
HTML
<body ng-controller="AppController">
<h1 ng-bind="product.product"></h1>
<br>
<button ng-click="openEditProductModal(product.product)">Open Modal</button>
<br>
<span ng-bind="product.product"></span>
</body>
Edit-Product.html
<div class="modal-header">
<h3><span class="glyphicon glyphicon-edit"></span> Edit Product</h3>
<span class="subtitle" ng-bind="product.name"></span>
</div>
<div class="modal-body edit-description-modal">
<div class="row">
<input ng-model="product.product"/>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">Save</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
Link to Plunkr