I am using this link to implement DropdownmultiSelect in my tutorial project.
Here how I define directive at my tutorial project:
(function () {
"use strict";
angular.module("gameBuilder").directive('dropdownMultiselect', [dropdownMultiselect]);
function dropdownMultiselect() {
return {
restrict: 'E',
scope: {
model: '=',
options: '=',
pre_selected: '=preSelected'
},
template: "<div class='btn-group' data-ng-class='{open: open}'>" +
"<button class='btn btn-small'>Select</button>" +
"<button class='btn btn-small dropdown-toggle' data-ng-click='open=!open;openDropdown()'><span class='caret'></span></button>" +
"<ul class='dropdown-menu' aria-labelledby='dropdownMenu'>" +
"<li><a data-ng-click='selectAll()'><i class='icon-ok-sign'></i> Check All</a></li>" +
"<li><a data-ng-click='deselectAll();'><i class='icon-remove-sign'></i> Uncheck All</a></li>" +
"<li class='divider'></li>" +
"<li data-ng-repeat='option in options'> <a data-ng-click='setSelectedItem()'>{{option.name}}<span data-ng-class='isChecked(option.id)'></span></a></li>" +
"</ul>" +
"</div>",
controller: function ($scope) {
$scope.openDropdown = function () {
$scope.selected_items = [];
for (var i = 0; i < $scope.pre_selected.length; i++) {
$scope.selected_items.push($scope.pre_selected[i].id);
}
};
$scope.selectAll = function () {
$scope.model = _.pluck($scope.options, 'id');
console.log($scope.model);
};
$scope.deselectAll = function () {
$scope.model = [];
console.log($scope.model);
};
$scope.setSelectedItem = function () {
var id = this.option.id;
if (_.contains($scope.model, id)) {
$scope.model = _.without($scope.model, id);
} else {
$scope.model.push(id);
}
console.log($scope.model);
return false;
};
$scope.isChecked = function (id) {
if (_.contains($scope.model, id)) {
return 'icon-ok pull-right';
}
return false;
};
}
}
}
})();
Here is controller definition:
(function () {
"use strict";
angular.module("gameBuilder", ["ui.router", "templates"])
.config([
"$stateProvider",
function ($stateProvider) {
$stateProvider
.state("gameBuilder", {
abstract: true,
url: "/gameBuilder",
template: "<ui-view></ui-view>"
})
.state("gameBuilder.list", {
url: "/",
templateUrl: "app/gameBuilder/templates/gameBuilderList.tmpl.html",
controller: "gameBuilderListController",
controllerAs: "list"
})
.state("gameBuilder.view", {
url: "/:gameId",
templateUrl: "app/gameBuilder/templates/gameBuilder.tmpl.html",
controller: "gameBuilderController",
controllerAs: "builder"
})
.state("gameBuilder.view.step1", {
url: '/step1',
templateUrl: "../app/gameBuilder/templates/NestedViews/FormStep1.html"
})
.state("gameBuilder.view.step2", {
url: '/step2',
templateUrl: "../app/gameBuilder/templates/NestedViews/FormStep2.html"
})
.state("gameBuilder.view.step3", {
url: '/step3',
templateUrl: "../app/gameBuilder/templates/NestedViews/FormStep3.html"
});
}
]);
})();
Here is how I use it in view:
<div class="form-group">
<dropdown-multiselect pre-selected="game.member.roles" model="game.selected_items" options="game.roles"></dropdown-multiselect>
<pre>
selected roles = {{game.selected_items | json}}
</pre>
</div>
But I get this error:
ReferenceError: _ is not defined
at Scope.$scope.isChecked (inspectionsBuilder.js:150)
at Object.$parseFunctionCall [as get] (angular.js:12332)
at Scope.$digest (angular.js:14217)
at Scope.$apply (angular.js:14488)
at done (angular.js:9646)
at completeRequest (angular.js:9836)
at XMLHttpRequest.requestLoaded (angular.js:9777)
Have you included underscore/lo-dash?
"ReferenceError: _ is not defined" usually appears when you haven't loaded library
You made a typo inside your isolate scope declaration, It should be preSelected instead of pre_selectedfollow the camel-casing also replace the $scope.pre_selected with $scope.preSelected
Code
scope: {
model: '=',
options: '=',
preSelected: '=preSelected' //<--change here
},
Related
In the code snippet I try to use a controller FooCtrl which is defined in the included template app/foo.html by using the directive common.script.
angular.module('common.script', []).directive('script', function() {
return {
restrict: 'E',
scope: false,
compile: function(element, attributes) {
if (attributes.script === 'lazy') {
var code = element.text()
new Function(code)()
}
}
}
})
angular.module('app.templates', ['app/foo.html'])
angular.module("app/foo.html", []).run(function($templateCache) {
$templateCache.put("app/foo.html",
"<script data-script=\"lazy\">\n" +
" console.log('Before FooCtrl')\n" +
" angular.module('app').controller('FooCtrl', function($scope) {\n" +
" console.log('FooCtrl')\n" +
" })\n" +
"<\/script>\n" +
"<div data-ng-controller=\"FooCtrl\">app\/foo.html\n" +
"<\/div>"
)
})
angular.module('app', ['common.script', 'app.templates']).controller('ApplicationCtrl', function($scope) {
console.log('ApplicationCtrl')
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<div data-ng-app="app" data-ng-controller="ApplicationCtrl">
<div data-ng-include="'app/foo.html'"></div>
</div>
But instead of the expected output FooCtrl in the console AngularJS throws:
Error: [ng:areq] Argument 'FooCtrl' is not a function [...]
I don't understand why! The code in the template is executed before the exception is thrown, thus the controller should be defined. How could I fix that?
The real problem here is lazy loading of resources! There are tons of material and related posts about this topic.
The solution here could be an extended common.script directive:
'use strict'
angular.module('common.script', [])
.config(function($animateProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
angular.module('common.script').lazy = {
$animateProvider: $animateProvider,
$controllerProvider: $controllerProvider,
$compileProvider: $compileProvider,
$filterProvider: $filterProvider,
$provide: $provide
}
})
.directive('script', function() {
return {
restrict: 'E',
scope: {
modules: '=script'
},
link: function(scope, element) {
var offsets = {}, code = element.text()
function cache(module) {
offsets[module] = angular.module(module)._invokeQueue.length
}
function run(offset, queue) {
var i, n
for (i = offset, n = queue.length; i < n; i++) {
var args = queue[i], provider = angular.module('common.script').lazy[args[0]]
provider[args[1]].apply(provider, args[2])
}
}
if (angular.isString(scope.modules)) {
cache(scope.modules)
} else if (angular.isArray(scope.modules)) {
scope.modules.forEach(function(module) {
cache(module)
})
}
/*jshint -W054 */
new Function(code)()
Object.keys(offsets).forEach(function(module) {
if (angular.module(module)._invokeQueue.length > offsets[module]) {
run(offsets[module], angular.module(module)._invokeQueue)
}
})
}
}
})
The only downside of this solution is that you have to specify the module(s) you want to extend in a script tag:
<script data-script="'app'">
angular.module('app').controller('FooCtrl', function($scope) {
console.log('Works!')
})
</script>
I have a directive element:
return {
restrict: 'E',
replace: true,
transclude: true,
template: '<ul>' +
'<li ng-show="hideItem">Home</li>' +
'<li ng-show="hideItem">Products</li>' +
'<li ng-show="!hideItem">Cart</li>' +
'<li ng-show="hideItem">Contact Us</li>' +
'</ul>',
link: function(scope, element, attrs) {
var shouldHide = myService.getData();
if (shouldHide === true) {
scope.hideItem = true
}
}
};
The link function performs a call to a service, the result is either true or false.
If true, i want hideItem to be set to true within my ng-show.
HTML structure:
<section ng-controller="NavigationController">
<i class="home"></i>
<i class="bell"></i>
<i class="phone"></i>
<my-directive></my-directive>
<button>Submit</button>
</section>
DEMO
you can actually just vm.hideItem = myService.getData(); since you want the boolean's value anyway
return {
restrict: 'E',
replace: true,
controllerAs: 'vm',
transclude: true,
template: '<ul>' +
'<li ng-show="vm.hideItem">Home</li>' +
'<li ng-show="vm.hideItem">Products</li>' +
'<li ng-show="!vm.hideItem">Cart</li>' +
'<li ng-show="vm.hideItem">Contact Us</li>' +
'</ul>',
link: function(scope, element, attrs, vm) {
vm.hideItem = myService.getData();
},
controller: function(){
}
};
I added controllerAs: 'vm' it's much more manageable by assigning a name to your controller and attach variables to it
You have to watch it :
scope.$watch(function(){
return myService.getData();
}, function(newValue){
scope.hideItem = newValue;
});
This is only if your service is not doing server-side requests, otherwise you'll spam the server.
I think getData method can be called from anywhere in your application.
And you want to keep track of these changes in your directive. In this case, you can use the callback.
Live example on jsfiddle.
angular.module('ExampleApp', [])
.controller('ExampleController', function($scope, myService) {
$scope.resolve = function() {
myService.getData().then(function() {
console.log('resolved from button resolve');
})
}
myService.getData().then(function() {
console.log('resolved from controller loading');
})
})
.directive('exampleDirective', function(myService) {
return {
restrict: "E",
scope: {
value: "="
},
template: `<div>hidden={{hidden}} value={{value}} <span ng-show="hidden">ng-show="hidden"</span><span ng-show="!hidden">ng-show="!hidden"</span></div>`,
link: function(scope) {
scope.hidden = false;
myService.addCallback(function(hideItem) {
scope.hidden = hideItem;
console.log('callback resolved with value ' + scope.value + ' and hide is ' + hideItem);
});
}
}
})
.service('myService', function($q, $timeout) {
var callbacks = [];
return {
getData: function() {
var defered = $q.defer();
//simulate $http call
$timeout(function() {
defered.resolve();
//simulate answer from server
var res = Math.round(Math.random() * 10) >= 5;
angular.forEach(callbacks, function(c) {
//call callback with result
$q.resolve(res, c);
});
}, 1000);
return defered.promise;
},
addCallback: function(callback) {
callbacks.push(callback);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController" id="ExampleController">
<button ng-click="resolve()">
call getData
</button>
<example-directive value="12"></example-directive>
<example-directive value="'ab'"></example-directive>
</div>
</div>
When you anywhere using the method of your getData directive knows that.
I dont understand why but when i console.log() both box and box.color its telling me its undefined...I tried many different methods to solve this problem but it all failed.
Cloud9
Plunker
And here is script.js:
var app = angular.module('LoginApp', ["firebase", "ngRoute", "ngCookies"])
app.provider("box", function ()
{
var hex = "SomeColor";
var UID = 3;
return {
setColor: function (value)
{
UID = value
},
$get: function ()
{
return {
color: hex
}
}
}
})
app.config(function ($routeProvider, $cookiesProvider) {
$routeProvider
.when('/', {
templateUrl: 'HtmlFiles/registration.html',
controller: 'regController'
})
.when('/logIn', {
templateUrl: 'HtmlFiles/login.html',
controller: 'loginController'
})
.when('/Chat', {
templateUrl: 'HtmlFiles/Chat.html',
controller: 'chatController'
})
.when('/Test' , {
template: '<h3>This is just a testing phase</h3>',
controller: 'Testing'
})
.when('/userSettings', {
templateUrl: 'HtmlFiles/userSettings.html',
controller: 'userSettingsController'
})
.when('/room', {
templateUrl: 'HtmlFiles/room.html',
controller: 'roomController'
})
.otherwise({
redirectTo: '/'
});
});
app.controller('Testing', ["$scope","roomService", "roomProvider", function($scope, roomService, roomProvider){
console.log("This is from the Controller Service: " + roomService.room.roomUID)
console.log("This is from the Controller Provider: " + roomProvider.$get)
}
])
app.factory("Auth", ["$firebaseAuth",
function($firebaseAuth) {
var ref = new Firebase("https://chattappp.firebaseio.com/");
return $firebaseAuth(ref);
}
]);
app.factory("Ref", function(){
var ref = new Firebase("https://chattappp.firebaseio.com/")
return ref;
})
app.factory("UniPosts" , function(){
var ref = new Firebase("https://postss.firebaseio.com/")
return ref;
});
app.service('getCookieService', ["$cookieStore", "$scope",
function($cookieStore, $scope){
this.getCookie = function(name){
$cookieStore.get(name)
}
}
])
roomController.js:
app.controller('roomController', ["$scope", "Auth", "Ref", "AuthService", "roomService","$http",
function($scope, Auth, Ref, AuthService, roomService, $http,box) {
// Sweet Alert :)
function generateRandomStringToken(length) {
var string = "";
var characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < length; i++){
string += characters.charAt(Math.floor(Math.random() * characters.length));
}
return string;
}
swal({
title: "Room",
text: "What do you want your room name to be?",
type: "input",
showCancelButton: true,
closeOnConfirm: false,
animation: "slide-from-top",
inputPlaceholder: "Write something"
}, function(inputValue) {
if (inputValue === false) return false;
if (inputValue === "") {
swal.showInputError("You need to write something!");
return false
}
swal("Nice!", "You wrote: " + inputValue, "success");
$scope.$apply(function () {
$scope.roomNameModel = inputValue
});
console.log($scope.roomNameModel)
var redirectPage = generateRandomStringToken(10)
console.log("User gets redirected to : " + redirectPage + " ...")
roomService.setRoomUID(redirectPage);
console.log(roomService.room.roomUID)
console.log(box) //Undefined...
console.log("From Provider : " + box.color)//box.color is undefined..
});
}
])
//window.location.hash = "/Test"
EDIT 2: Ok Now it works but im confused on how to use it on app.config.. i My provider is Hash:
app.provider("Hash", function ()
{
var UID = 0;
return {
$get: function ()
{
return {
setHash: function (value)
{
UID = value;
},
getHash: function()
{
return UID;
}
}
}
}
})
And when it goes to the controller i set the hash and get the has ... roomControler.js:
app.controller('roomController', ["$scope", "Auth", "Ref", "AuthService", "roomService","$http", "Hash",
function($scope, Auth, Ref, AuthService, roomService, $http,Hash) {
// Sweet Alert :)
function generateRandomStringToken(length) {
var string = "";
var characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < length; i++){
string += characters.charAt(Math.floor(Math.random() * characters.length));
}
return string;
}
swal({
title: "Room",
text: "What do you want your room name to be?",
type: "input",
showCancelButton: true,
closeOnConfirm: false,
animation: "slide-from-top",
inputPlaceholder: "Write something"
}, function(inputValue) {
if (inputValue === false) return false;
if (inputValue === "") {
swal.showInputError("You need to write something!");
return false
}
swal("Nice!", "You wrote: " + inputValue, "success");
$scope.$apply(function () {
$scope.roomNameModel = inputValue
});
console.log($scope.roomNameModel)
var redirectPage = generateRandomStringToken(10)
console.log("User gets redirected to : " + redirectPage + " ...")
roomService.setRoomUID(redirectPage);
console.log(roomService.room.roomUID);
Hash.setHash(redirectPage);
console.log("From Provider : " + Hash.getHash())
window.location.hash = "/Test"
});
}
])
Now what i want to do is in my app.config() i want to say when it is in Hash.getHash() Go to template: , and controller:
So something like this....
app.config(function ($routeProvider, $cookiesProvider, Hash) {
$routeProvider.
when('/' + Hash.getHash(), {
template: '<h4> Your in Room',
controller: 'Test
})
});
app.controller('Testing', ["$scope","roomService","Hash",function($scope, roomService, Hash){
console.log("This is from the Controller Service: " + roomService.room.roomUID)
console.log(Hash.getHash())//This Logs right. :D
}
])
EDIT 3
What i was trying to say earlier was that i want to somehow configure the randomly generated Hash in my app.config() when statements. so in my app.config. WHEN the USER is in /RANDOMLYGENERATEDHASH have a template: '<h1>Test</h1>' . This is what i tried but dosent workk...
It is the fourth one on the .when() Statements..
app.config(function ($routeProvider, $cookiesProvider, HashProvider){
$routeProvider
.when('/', {
templateUrl: 'HtmlFiles/registration.html',
controller: 'regController'
})
.when('/logIn', {
templateUrl: 'HtmlFiles/login.html',
controller: 'loginController'
})
.when('/Chat', {
templateUrl: 'HtmlFiles/Chat.html',
controller: 'chatController'
})
.when('/' + HashProvider , {
templete: '<h1>Test</h1>'
})
.when('/userSettings', {
templateUrl: 'HtmlFiles/userSettings.html',
controller: 'userSettingsController'
})
.when('/room', {
templateUrl: 'HtmlFiles/room.html',
controller: 'roomController'
})
.otherwise({
redirectTo: '/'
});
});
And here is the provider now..
app.provider("Hash", function ()
{
var UID = 0;
var _getHash = function()
{
return UID;
};
return {
getHash: _getHash,
$get: function ()
{
return {
setHash: function (value)
{
UID = value;
},
getHash: _getHash
}
}
}
})
EDIT 4
Ok This is my roomcontroller.js Now..:
(Important detail at bottom of controller)
app.controller('roomController', ["$scope", "Auth", "Ref", "AuthService", "roomService","$http", "Hash","$routeParams",
function($scope, Auth, Ref, AuthService, roomService, $http,Hash, $routeParams) {
// Sweet Alert :)
function generateRandomStringToken(length) {
var string = "";
var characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < length; i++){
string += characters.charAt(Math.floor(Math.random() * characters.length));
}
return string;
}
swal({
title: "Room",
text: "What do you want your room name to be?",
type: "input",
showCancelButton: true,
closeOnConfirm: false,
animation: "slide-from-top",
inputPlaceholder: "Write something"
}, function(inputValue) {
if (inputValue === false) return false;
if (inputValue === "") {
swal.showInputError("You need to write something!");
return false
}
swal("Nice!", "You wrote: " + inputValue, "success");
$scope.$apply(function () {
$scope.roomNameModel = inputValue
});
console.log($scope.roomNameModel)
var redirectPage = generateRandomStringToken(10)
console.log("User gets redirected to : " + redirectPage + " ...")
roomService.setRoomUID(redirectPage);
console.log(roomService.room.roomUID);
Hash.setHash(redirectPage);
console.log("From Provider : " + Hash.getHash())
$routeParams.hash = Hash.getHash()
});
}
])
and script.js(Note this is not the only ones i have. You can see all other on above link on Cloud9(Plunk not updated)):
var app = angular.module('LoginApp', ["firebase", "ngRoute", "ngCookies", 'ngMessages'])
app.provider("Hash", function ()
{
var UID = 0;
var _getHash = function()
{
return UID;
};
return {
getHash: _getHash,
$get: function ()
{
return {
setHash: function (value)
{
UID = value;
},
getHash: _getHash
}
}
}
})
app.config(function ($routeProvider, $cookiesProvider, HashProvider){
$routeProvider
.when('/', {
templateUrl: 'HtmlFiles/registration.html',
controller: 'regController'
})
.when('/logIn', {
templateUrl: 'HtmlFiles/login.html',
controller: 'loginController'
})
.when('/Chat', {
templateUrl: 'HtmlFiles/Chat.html',
controller: 'chatController'
})
.when('/:Hash', {
template: '<h1>TEST TEST</h1>',
controller: 'any controller'
})
.when('/userSettings', {
templateUrl: 'HtmlFiles/userSettings.html',
controller: 'userSettingsController'
})
.when('/room', {
templateUrl: 'HtmlFiles/room.html',
controller: 'roomController'
})
.otherwise({
redirectTo: '/'
});
});
app.controller('Testing', ["$scope","roomService","Hash",function($scope, roomService, Hash){
console.log("This is from the Controller Service: " + roomService.room.roomUID)
console.log(Hash.getHash())
}
])
app.factory("Auth", ["$firebaseAuth",
function($firebaseAuth) {
var ref = new Firebase("https://chattappp.firebaseio.com/");
return $firebaseAuth(ref);
}
]);
app.factory("Ref", function(){
var ref = new Firebase("https://chattappp.firebaseio.com/")
return ref;
})
app.factory("UniPosts" , function(){
var ref = new Firebase("https://postss.firebaseio.com/")
return ref;
});
app.service('getCookieService', ["$cookieStore", "$scope",
function($cookieStore, $scope){
this.getCookie = function(name){
$cookieStore.get(name)
}
}
])
[1]: https://ide.c9.io/amanuel2/chattapp
[2]: https://plnkr.co/edit/ToWpQCw6GaKYkUegFjMi?p=preview
There are two problems in your code:
Definition of "roomController"
app.controller('roomController', ["$scope", "Auth", "Ref",
"AuthService", "roomService","$http",
function($scope, Auth, Ref, AuthService, roomService,
$http,box) {})
Just match the parameters and their declarations and you will see that you missed a declaration for the "box" parameter. The correct "roomController" definition should be like this:
app.controller('roomController', ["$scope", "Auth", "Ref", "AuthService", "roomService","$http", "box",
function($scope, Auth, Ref, AuthService, roomService, $http,box)
"box" provider. You defined "setColor" method as the configuration method of provider, but you are trying to use it as a provider result method. The corrected version should be like this:
app.provider("box", function ()
{
var hex = "SomeColor";
var UID = 3;
return {
$get: function ()
{
return {
color: hex,
setColor: function (value)
{
UID = value
}
}
}
}
})
Angular Providers
Answer to EDIT2:
You defined HashProvider. To configure it in app.config you should pass argument as HashProvider (not just Hash, BUT when you will try to use it anywhere except app.config you should inject it as Hash). So your app.config declaration should be like this:
app.config(function ($routeProvider, $cookiesProvider, HashProvider)
...and to let you access the getHash method it's necessary to move it to the provider configuration, for example like this:
app.provider("Hash", function ()
{
var UID = 0;
var _getHash = function()
{
return UID;
};
return {
getHash: _getHash,
$get: function ()
{
return {
setHash: function (value)
{
UID = value;
},
getHash: _getHash
}
}
}
})
Answer to EDIT3:
Now I got what you are trying to do. And the thing is that you are trying to do it wrong :). The right way is more simple. You have to configure route with param, for example like this:
.when('/:hash', {
template: '<h1>TEST TEST</h1>',
controller: 'any controller'
})
And place it just after your last route. After that, in controller you may access hash by using $routeParams object. For example like this:
$routeParams.hash
And after that in controller you may analyze if it's right hash and do necessary stuff, or redirect user somewhere if hash is invalid.
i am using angularjs-ui tabs in my app.
angular.module('bootstrap.tabset', [])
.directive('tekplntabsets',['tabsetServ', function (tabsetServ) {
return {
restrict: 'E',
replace: true,
transclude: true,
controller: function ($scope) {
$scope.templateUrl = '';
var tabs = $scope.tabs = [];
var controller = this;
this.selectTab = function (tab) {
angular.forEach(tabs, function (tab) {
tab.selected = false;
});
tab.selected = true;
tabsetServ.setTabId(tab.tabid);
};
this.setTabTemplate = function(templateUrl) {
$scope.templateUrl = templateUrl;
};
this.setTabController = function(tabCtrl) {
$scope.tabCtrl = tabCtrl;
};
this.getTabController = function() {
return $scope.tabCtrl;
};
this.removeTab = function(tab) {
var index = tabsetServ.removeTab(tab);
this.selectTab(tabs[index - 1]);
};
this.addTab = function (tab) {
if (tabs.length == 0) {
controller.selectTab(tab);
}
tabs.push(tab);
controller.selectTab(tab);
};
},
template:
'<div class="row-fluid flexbox flexboxContent divHeight100">' +
'<div class="row-fluid">' +
'<div class="nav nav-tabs" ng-transclude></div>' +
'</div>' +
'<div class="row-fluid flexbox flexboxContent divHeight100">' +
'<ng-include src="templateUrl" class="flexbox flexboxContent divHeight100" ></ng-include>' +
'</div>' +
'</div>'
};
}])
.directive('tekplntab', function () {
return {
restrict: 'E',
replace: true,
require: '^tekplntabsets',
scope: {
title: '#',
templateUrl: '#',
tabid: '#',
closable: '#',
tabicon: '#',
controller:'#'
},
link: function (scope, element, attrs, tabsetController, $route) {
tabsetController.addTab(scope);
scope.select = function () {
tabsetController.selectTab(scope);
};
scope.$watch('selected', function () {
if (scope.selected) {
tabsetController.setTabTemplate('');
tabsetController.setTabTemplate(scope.templateUrl);
// scope.$apply();
//$route.reload();
//if (scope.$parent.tektab.ctrl !== "" && scope.$parent.tektab.ctrl !== "DashboardCtrl") {
// var ctrl = scope.$parent.tektab.ctrl;
// scope.$parent.tektab.ctrl = "";
// scope.$parent.tektab.ctrl = ctrl;
//}
//if (scope.$root.$$phase !== '$digest' && scope.$$phase !== '$digest') {
// scope.$apply();
// }
//scope.$watch('scope.tabid', function (randomValue) {
// scope.$apply();
//}); ng-controller="{{controller}}"
}
});
scope.removeTab = function (id) {
tabsetController.removeTab(id);
};
},
template:
'<li ng-class="{active: selected}" >' +
'<a href="" ng-click="select()"><div class="pointerDiv {{ tabicon }}" ng-show="{{closable}}"></div> {{ title }} ' +
'<button ng-click="removeTab(title)" class="TabClose" ng-show="{{closable}}">x</button></a>' +
'<input type="hidden" value="{{ tabid }}"></input>' +
'</li>'
};
});
When I am using this directive to open 2 tabs that use different controllers it works well.
The problem occurs when I want to switch between 2 tabs that using same controller. (for example, when I open 2 different projects and I want to switch between project number 1 and project number 2, the tab does not load all the data from project number 2 !!).
I don't want to use angular-ui-router.
project 1 and project 2 uses same partial html
I managed to solve the problem by using Boradcasting messages
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