How to dismiss an angularjs alert when user changes route/state - angularjs

I am using this angular js service/directive github pageto display alerts. An issue has been opened relating to the question I am asking but it has not been addressed by the developer.
i want first alert shown when user logs in to disappear when the user clicks logout but the alerts are stacking up on top of each other.
Here is a fiddle although I could not replicate the issue but it shows the structure of my code. fiddle
html:
<body ng-app="app">
<mc-messages></mc-messages>
<button ng-click="login()">Login</button>
<button ng-click="logout()">Logout</button>
</body>
js:
/*jshint strict:false */
'use strict';
var app = angular.module('app', ['MessageCenterModule']);
app.controller(function ($scope, messageCenterService, $location) {
$scope.login = function () {
$location.path('/');
messageCenterService.add('success',
'You are now loggedin!', {
status: messageCenterService.status.next
});
};
$scope.logout = function () {
$location.path('login');
messageCenterService.add('success',
'You are now loggedout!', {
status: messageCenterService.status.next
}
};
});
// Create a new angular module.
var MessageCenterModule = angular.module('MessageCenterModule', []);
// Define a service to inject.
MessageCenterModule.
service('messageCenterService', ['$rootScope', '$sce', '$timeout',
function ($rootScope, $sce, $timeout) {
return {
mcMessages: this.mcMessages || [],
status: {
unseen: 'unseen',
shown: 'shown',
/** #var Odds are that you will show a message and right after that
* change your route/state. If that happens your message will only be
* seen for a fraction of a second. To avoid that use the "next"
* status, that will make the message available to the next page */
next: 'next',
/** #var Do not delete this message automatically. */
permanent: 'permanent'
},
add: function (type, message, options) {
var availableTypes = ['info', 'warning', 'danger', 'success'],
service = this;
options = options || {};
if (availableTypes.indexOf(type) === -1) {
throw "Invalid message type";
}
var messageObject = {
type: type,
status: options.status || this.status.unseen,
processed: false,
close: function () {
return service.remove(this);
}
};
messageObject.message = options.html ? $sce.trustAsHtml(message) : message;
messageObject.html = !! options.html;
if (angular.isDefined(options.timeout)) {
messageObject.timer = $timeout(function () {
messageObject.close();
}, options.timeout);
}
this.mcMessages.push(messageObject);
return messageObject;
},
remove: function (message) {
var index = this.mcMessages.indexOf(message);
this.mcMessages.splice(index, 1);
},
reset: function () {
this.mcMessages = [];
},
removeShown: function () {
for (var index = this.mcMessages.length - 1; index >= 0; index--) {
if (this.mcMessages[index].status == this.status.shown) {
this.remove(this.mcMessages[index]);
}
}
},
markShown: function () {
for (var index = this.mcMessages.length - 1; index >= 0; index--) {
if (!this.mcMessages[index].processed) {
if (this.mcMessages[index].status == this.status.unseen) {
this.mcMessages[index].status = this.status.shown;
} else if (this.mcMessages[index].status == this.status.next) {
this.mcMessages[index].status = this.status.unseen;
}
this.mcMessages[index].processed = true;
}
}
},
flush: function () {
$rootScope.mcMessages = this.mcMessages;
}
};
}]);
MessageCenterModule.
directive('mcMessages', ['$rootScope', 'messageCenterService', function ($rootScope, messageCenterService) {
/*jshint multistr: true */
var templateString = '\
<div id="mc-messages-wrapper">\
<div class="alert alert-{{ message.type }} {{ animation }}" ng-repeat="message in mcMessages">\
<a class="close" ng-click="message.close();" data-dismiss="alert" aria-hidden="true">×</a>\
<span ng-switch on="message.html">\
<span ng-switch-when="true">\
<span ng-bind-html="message.message"></span>\
</span>\
<span ng-switch-default>\
{{ message.message }}\
</span>\
</div>\
</div>\
';
return {
restrict: 'EA',
template: templateString,
link: function (scope, element, attrs) {
// Bind the messages from the service to the root scope.
messageCenterService.flush();
var changeReaction = function (event, to, from) {
// Update 'unseen' messages to be marked as 'shown'.
messageCenterService.markShown();
// Remove the messages that have been shown.
messageCenterService.removeShown();
$rootScope.mcMessages = messageCenterService.mcMessages;
messageCenterService.flush();
};
$rootScope.$on('$locationChangeStart', changeReaction);
scope.animation = attrs.animation || 'fade in';
}
};
}]);
Hope this is clear enough for someone to help me. If not let me know and I can try to clarify.

Related

Select Always Returning First Item of List (AngularJS)

No matter what I select, this function only returns the first item of the list. As requested, I have included the complete JS code. I have looked through this code four hours and everything seems right to me. This is my first contact with Angular and any help will be greatly appreciated!
Thank you!
HTML
<div class="form-horizontal input-append">
<select name="selectedSharedTenantId" data-ng-model="selectedSharedTenantId">
<option data-ng-repeat="item in getFilteredTenants()" value="{{item.id}}">{{item.displayName}}</option>
</select>
<button type="button" class="btn" ng-click="addSharedTenant();">
<i class="fas fa-plus"></i>
</button>
</div>
JS
$scope.addSharedTenant = function () {
alert($scope.selectedSharedTenantId)
}
COMPLETE JS CODE
angular.module('directives.datasetEditor', [
'services.dataset',
'ui.bootstrap'
])
.directive('datasetEditor', ['$modal', 'DatasetServices', function ($modal, DatasetServices) {
return {
restrict: 'A',
scope: {
tenantId: '=',
tenants: '=',
originalModel: '=model',
callback: '&callback'
},
link: function(scope, element, attrs) {
scope.model = scope.originalModel ? angular.copy(scope.originalModel) : {
entryType: 'Activity',
displayName: ''
};
var ModalInstanceCtrl = ['$scope', '$modalInstance',
function($scope, $modalInstance) {
var setSelectedSharedTenantId = function () {
var selectedTenant = $scope.getFilteredTenants()[0];
$scope.selectedSharedTenantId = selectedTenant ? selectedTenant.id : null;
};
$scope.getFilteredTenants = function () {
return _.filter($scope.tenants, function (o) {
alert(o.id)
return _.indexOf($scope.model.sharedTenantIds, o.id) == -1 && o.id != $scope.tenantId;
});
};
$scope.getTenantById = function (id) {
return _.findWhere($scope.tenants, {
id: id
});
};
$scope.removedSharedTenant = function (id) {
$scope.model.sharedTenantIds = _.without($scope.model.sharedTenantIds, id);
var selectedTenant = $scope.getFilteredTenants()[0];
setSelectedSharedTenantId();
};
$scope.addSharedTenant = function () {
//alert($scope.selectedSharedTenantId)
//alert($scope.model.sharedTenantIds)
if ($scope.selectedSharedTenantId) {
if ($scope.model.sharedTenantIds == null) {
$scope.model.sharedTenantIds = [];
}
$scope.model.sharedTenantIds.push($scope.selectedSharedTenantId);
setSelectedSharedTenantId();
}
};
$scope.submit = function(isValid) {
if (isValid) {
DatasetServices.save($scope.model).success(function(data, status, headers, config) {
$modalInstance.close(data);
});
} else {
$scope.submitted = true;
}
};
$scope.cancel = function() {
$modalInstance.dismiss();
};
$scope.submitted = false;
setSelectedSharedTenantId();
}];
function open() {
var modalInstance = $modal.open({
templateUrl: '../pkg/wisdom/common/angular/directives/dataset-editor/index.html',
controller: ModalInstanceCtrl,
scope: scope
});
modalInstance.result.then(
function(model) {
scope.callback({
model: model
});
},
function() {
}
);
};
element.on('click', open);
}
};
}]);

Scope from controller does not pass to directive

I have a html like this :
<div id="create-group" ng-controller="groupCreateController">
<div id="container">
<h1>Create group</h1>
<div class="row">
<div class="col-md-4"><input placeholder="Group Name.." ng-model="group.name"></div>
<div class="col-md-8">
<label>Group Description : </label>
<textarea ng-model="group.description"> </textarea>
</div>
</div>
<br/>
<div class="row">
<div class="col-sm-6">
<usermgr-permission-list group="group"></usermgr-permission-list>
<button type="button" class="btn btn-md btn-primary" ng-click="btnSave_click($event)">SAVE</button>
</div>
<div class="col-sm-6">
<usermgr-user-list group="group"></usermgr-user-list>
</div>
</div>
</div>
</div>
My controller is :
(function (module) {
'use strict';
module.controller('groupCreateController', function ($scope, $rootScope, $routeParams, $location, userGroupService, $mdDialog) {
$scope.group = [];
$scope.init = function () {
if ($routeParams.hasOwnProperty('id')) {
//edit mode
// $scope.trans.heading = 'Edit Release';
// $scope.trans.saveBtn = 'Save';
var id = parseInt($routeParams.id);
getUserGroup(id);
} else {
$scope.group[0].id = 0;
$scope.group[0].permissions = [];
$scope.assignedPermissions = [];
$scope.enrolledUsers = [];
$scope.group[0].users = [];
$scope.group[0].name = '';
$scope.group[0].description = '';
}
};
function getUserGroup(id) {
userGroupService.getbyid(id).then(function (info) {
if (info !== undefined && info.id === id) {
$scope.group[0].id = info.id;
$scope.group[0].name = info.name;
$scope.group[0].description = info.description;
console.log($scope.group);
// $rootScope.$broadcast('rCube-user-mgt-users-list', info.id);
// $rootScope.$broadcast('rCube-user-mgt-permissions-list', info.id);
}
else {
}
}).catch(function (exception) {
console.error(exception);
});
}
$scope.init();
});
})(angular.module('r-cube-user-mgt.user-group'));
I have two custom directives in the first block of code for user permissions and users. The group scope that i pass with the directive does not contain the values i put in the getUserGroup(id) function. The group name and group description shows up so the scope.group in the controller is filled, however thats not the case once i pass it to my directives. here is the directives code as well :
permissions list :
(function (module) {
'use strict';
module.directive('usermgrPermissionList', function () {
return {
restrict: 'E',
scope:{
group: '='
},
controller: function ($scope, permissionService) {
$scope.updatedPermissions=[];
console.log($scope.group); //it doesnt have the values from the controller ..
if (!$scope.group.hasOwnProperty('permissions')) {
$scope.group.permissions = [];
}
function getData() {
console.log("inside getDAta for permission list" + $scope.group.id;
permissionService.getPermissionsFiltered($scope.group.id).then(function (info) {
if (info && info.length > 0) {
console.log(info);
$scope.group.permissions = info.map(function (a, index, array) {
return {
id: a.id,
name: a.name,
description: a.description,
assigned: a.assigned
};
});
}
}).catch(function (exception) {
console.error(exception);
});
} //end of getData()
$scope.init = function () {
getData();
};
$scope.init();
},
templateUrl: 'r-cube-user-mgt/permission/list/list.tpl.html'
};
});
})(angular.module('r-cube-user-mgt.permission'));
can anyone help?
you cannot assign property to an array like this $scope.group.id = 0;
either make $scope.group object
$scope.group = {};
or add properties to an index
$scope.group = [];
$scope.init = function () {
if ($routeParams.hasOwnProperty('id')) {
//edit mode
// $scope.trans.heading = 'Edit Release';
// $scope.trans.saveBtn = 'Save';
var id = parseInt($routeParams.id);
getUserGroup(id);
} else {
$scope.group[0].id = 0;
$scope.group[0].permissions = [];
$scope.assignedPermissions = [];
$scope.enrolledUsers = [];
$scope.group[0].users = [];
$scope.group[0].name = '';
$scope.group[0].description = '';
}
};
So I solved the issue by adding broadcast to send the id when the directive loads. This worked!
in the Group controller i add broadcast and send the group.id
function getUserGroup(id) {
userGroupService.getbyid(id).then(function (info) {
if (info !== undefined && info.id === id) {
$scope.group.id = info.id;
$scope.group.name = info.name;
$scope.group.description = info.description;
console.log($scope.group);
$rootScope.$broadcast(rCubeTopics.userMgtPermissionLoadData, $scope.group.id);
}
}).catch(function (exception) {
console.error(exception);
});
}
and in the permission directive get that broadcast :
$scope.$on(rCubeTopics.userMgtPermissionLoadData, function (event, id) {
console.log($scope.group.id);
getData();
});

ng-repeat producing unexpected and strange results

I have spent a good 5-6 hours trying to figure this out, and I don't know why simply showing one object in an ng-repeat is being duplicated 10 times. Also the values aren't being output.
$scope looks like this
↪ projects (this loads up on demand)
↪ activeProjects (this is one object) and this used in the view
↪ setActiveProject(id,scope) passed along to the <projectpick> directive
Please could someone take a quick look at http://bit.ly/1TQxQW2
Click any project in the right hand column and observe the output.
Edit: added the js - omitted stuff which is not necessary. Another way to look at this question is how do you debug the ng-repeat loop?
(function() {
'use strict';
var DATA_KEY_PREFIX = 'project_',
AJAX_EVENT_PREFIX = 'projectsService';
angular.module('projectsApp', []).controller('ProjectsController', ['$scope', 'appUtils', '$timeout', function($scope, utils, $timeout) {
$scope.projects = [];
$scope.ajaxPojectsIsLoading = false;
$scope.activeProjects = [];
$scope.$watch('activeProjects', function(newProject, oldProject) {
$scope.ajaxPojectsIsLoading = false;
// user has changed focus on the current project so update
if (newProject !== oldProject) {
$scope.setActiveProject(newProject, $scope);
console.log('setting project to active' , newProject , $scope);
}
});
$scope.$on(AJAX_EVENT_PREFIX + '.get', function(e, data) {
$scope.ajaxPojectsIsLoading = true;
});
$scope.$on(AJAX_EVENT_PREFIX + '.done', function(e, data) {
console.log('activeProjects.done', $scope.activeProjects);
});
$scope.$on('mapMarker.click', function(e, marker) {
$scope.$apply(function() {
$scope.activeProjects = $scope.projects[marker.id];
});
});
}])
/*
* directive projectpick
* #dep {Object} SquizApiFactory - factory to provide the calls to/from squiz cms
* #return {Object} after ajax request passes back data object for rest of application.
* */
.directive('projectpick', ['projectsService', '$timeout', 'appUtils', function(projectsService, $timeout, utils) {
/*
* loadProject
* #scope
*
* */
function loadProject(scope) {
try {
var elementText = this.text().trim(),
ngModel = this.attr('ng-model'),
id = +this.attr('projectpick');
if (!angular.isNumber(id)) {
throw new Error('id must be a Number, ' + typeof id + ' passed in');
}
// bundle up the raw server data with directive's attributes and update the scope.
var handleProjectData = function(data) {
scope[ngModel][id] = angular.extend({
name: elementText,
id: id
}, data);
scope['active' + utils.capitaliseFirstLetter(ngModel)] = scope[ngModel][id];
}
// check to see if the data is already cached
if (angular.isDefined(scope[ngModel][id])) {
handleProjectData(scope[ngModel][id]);
} else {
projectsService.get(id).then(handleProjectData);
}
} catch (e) {
console.log(e.stack);
}
}
/*
* getProject
* #todo refactor this shit implementation
* #param id
* */
function setActiveProject(id, scope) {
var element = angular.element(document.querySelector('[projectPick="' + id + '"]'));
if (angular.isElement(element) && element.length) {
loadProject.call(element, scope);
}
}
return {
restrict: 'AE',
link: function(scope, element, attr) {
scope.setActiveProject = setActiveProject;
element.bind('click', function(e) {
e.preventDefault();
loadProject.call(element, scope);
});
}
}
}]).directive('loader', function() {
return {
restrict: 'E',
templateUrl: 'templates/loader.html',
replace: true,
scope: {
src: '#src',
content: '#content'
}
}
})
/*
* asDate
* #param String input
* #return Number as timestamp
* */
.filter("asDate", function() {
...
})
/*
* proejctsService
* API wrapper around the SquizApi.
* #Events - before and after ajax has finished
* #Methods: get
* ↪ calls getMetadata method
*
* #return Promise
* */
.service('projectsService', ['$rootScope', '$q', 'fakeSquizApiFactory', 'appUtils', function($rootScope, $q, squizApiFactory, utils) {
var squizApi = squizApiFactory();
return {
get: function(id) {
var defer = $q.defer();
$rootScope.$apply(function() {
$rootScope.$broadcast(AJAX_EVENT_PREFIX + '.get', {
data: id
});
});
squizApi.getMetadata({
asset_id: id,
dataCallback: function(data) {
if (data.hasOwnProperty('error')) {
defer.reject(data.error);
}
data = utils.tidyJSONKeys(data, DATA_KEY_PREFIX);
defer.resolve(data);
$rootScope.$apply(function() {
$rootScope.$broadcast(AJAX_EVENT_PREFIX + '.done', {
data: data
});
});
}
});
return defer.promise;
}
}
}])
/*
* appUtils
* contains useful/necessary functions in order to make this app work
* #return
* */
.factory('appUtils', [function() {
return {
tidyJSONKeys: function(arry, stringReplace) {
...
},
capitaliseFirstLetter: function(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
};
}])
.factory('fakeSquizApiFactory', function squizApiFactory() {
var Squiz_Matrix_API = new Function;
Squiz_Matrix_API.prototype.getMetadata = function(args) {
if (args.hasOwnProperty('dataCallback')) {
setTimeout(function() {
args.dataCallback.call({}, {
project_area: "Metro",
project_body: "...",
project_cost: "100",
project_image: "29031",
project_link: "http://nbhsredev.health.nsw.gov.au/",
project_end_date: "2017-05-03 00:00:00",
project_start_date: "2016-01-01 00:00:00",
project_status: "progress"
});
}, 150);
}
};
return function(apiOptions) {
apiOptions = angular.extend({
key: SQUIZ_API_KEY
}, apiOptions || {});
return new Squiz_Matrix_API(apiOptions);
};
}).directive('gmap', ['GMapsService', '$http', '$rootScope', function(gmaps, $http, $rootScope) {
var map;
var link = function(scope, element, attr) {
try {
var id = element.children(':first').prop('id'),
gmapParams = {},
props = JSON.parse(attr.params);
if (id && props) {
init(id, props, scope);
} else {
throw new Error('gmap expects a json string parsed into attribute params');
}
} catch (e) {
console.log(e.stack);
}
}
var controller = function($scope) {
this.addMarkers = addMarkers, this.panTo = panTo
}
function init(id, props, scope) {
map = new gmaps(angular.extend({
div: '#' + id
}, props));
if (scope.modelUrl) {
$http.get(scope.modelUrl).then(function(response) {
addModel.call(scope, response);
addMarkers(formatModelForGMap(scope.model, $rootScope));
}, handleError);
}
}
function addModel(ajaxResp) {
if (ajaxResp.hasOwnProperty(('data'))) {
this.model = ajaxResp.data;
}
}
function handleError(err) {
}
/*
* formatModelForGMap
* transforms the model to be compatible for gmaps
* #link https://hpneo.github.io/gmaps/examples/markers.html
* #events marker.click as we don't want to put a ng-click on the marker itself.
* {
* lat: -12.043333,
* lng: -77.028333,
* title: 'Lima',
* click: function(e) {},
* infoWindow: {}
*
}
* */
function formatModelForGMap(model, $rootScope) {
return model.map(function(location) {
...
}
})
}
/*
* addMarkers
* wrapper around the addMarkers method on GMap
* return map;
* */
function addMarkers(arrGMapParams) {
...
}
function panTo(marker, zoomLevel) {
...
}
return {
restrict: 'E',
scope: {
params: '#params',
modelUrl: '#modelUrl',
projectChange: '&'
},
transclude: true,
replace: true,
controlller: controller,
link: link
}
}]).service('GMapsService', function() {
return function(params) {
return new GMaps(params);
}
});
}());
HTML:
<div id="projects-side-links">
<ul class="projects-search__list scrollable">
<li>
<button projectpick="29112" ng-model="projects" class="projects-search__quick-button regional">Armidale Hospital Redevelopment</button>
</li>
<li>
<button projectpick="29096" ng-model="projects" class="projects-search__quick-button regional">Kempsey District Hospital</button>
</li>
<li>
<button projectpick="29100" ng-model="projects" class="projects-search__quick-button metro">Northern Beaches Health Service Redevelopment (Community Health Services)</button>
</li>
<li>
<button projectpick="29116" ng-model="projects" class="projects-search__quick-button regional">Shellharbour Ambulatory Care</button>
</li>
<li>
<button projectpick="29104" ng-model="projects" class="projects-search__quick-button metro">Prince of Wales - Reconfiguration and Expansion</button>
</li>
<li>
<button projectpick="29108" ng-model="projects" class="projects-search__quick-button metro">The Bright Alliance</button>
</li>
</ul>
</div>
<loader ng-show="ajaxPojectsIsLoading" src="mysource_files/ajax-loader.gif" content="Retrieving content..."></loader>
<div class="projects-search-results__container" ng-cloak ng-repeat="project in activeProjects">
<h1>{{$index + 1}}</h1>
<div class="projects-search-results__wrapper">
<div ng-show="project.image" class="js-result-thumbnail projects-search-results__image">
<img ng-src="./?a={{project.image}}" alt="{{project.name}}">
</div>
<div class="projects-search-results__details">
<h2 class="js-result-name project-search-results__name">{{project.name}}</h2>
<p class="projects-search-results__area">
<span class="js-result-area">{{project.area}}</span> Area
</p>
<p class="projects-search-results__status">
Project Status - <span class="js-result-status">{{project.status}}</span>
</p>
<div class="js-result-description projects-search-results__description">
{{project.body}}
<p>
Click here for more information.
</p>
</div>
<ul class="projects-search-results__list">
<li class="projects-search-results__link icon-globe">
{{project.link}}
</li>
<li ng-show="project.start_date" class="projects-search-results__list-item icon-clock">
<time>{{ project.start_date | asDate | date:'MMMM yyyy'}}</time>
<time ng-show="project.end_date"> — {{ project.end_date | asDate | date:'MMMM yyyy'}}</time>
</li>
<li ng-show="project.cost" class="projects-search-results__list-item icon-cost">
{{project.cost}} Million
</li>
</ul>
</div>
</div>
Use $scope.$watchcollection instead of $scope.$watch
$scope.$watchcollection('activeProjects', function(newProject, oldProject) {
$scope.ajaxPojectsIsLoading = false;
// user has changed focus on the current project so update
if (newProject !== oldProject) {
$scope.setActiveProject(newProject, $scope);
console.log('setting project to active' , newProject , $scope);
}
});

Modal Factory to be used in place of Confirm()

I have created an Angular Modal factory that passes a couple parameters to create dynamic modals based upon templates and options passed back. However I want to replace all of the Confirm dialogues in my app but am struggling with this.
modal factory
(function () {
var testApp= angular.module('test');
testApp.factory('myModals', ['$uibModal', function ($uibModal) {
// called from various methods within factory
function openModal(template, data, options) {
//build all of the modal options
var modalOpts = {
animation: true,
templateUrl: template,
controller: function ($scope, $uibModalInstance, alert_data) {
$scope.alert_data = alert_data;
$scope.okToProceed = function () {
$scope.goodToGo = true;
console.log("true")
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
console.log("modal cancelled")
};
},
resolve: {
alert_data: data
},
size: '480',
backdrop: 'static'
};
// extend options set in each use type function
if (options) {
angular.extend(modalOpts, modalOpts);
}
var modalInstance = $uibModal.open(modalOpts);
modalInstance.result.then(function (data) {
// always do something when close called
return data;
}, function (data) {
//always do something when dismiss called
return data
});
return modalInstance;
}
function alert(type, text, size) {
var template;
// enter in template and string being passed back to identify modal type
switch (type) {
case 'test1':
template = 'test1.popup.html';
break;
case 'test2':
template = 'test2.popup.html';
break;
}
var opts = {
//default but should be passed back
size: size || 'sm'
};
var data = {
title: type === 'success' ? "OK" : "Error",
text: text
};
return openModal(template, data, opts);
}
return {
alert: alert
}
}])
})();
template.html
<div class="modal-header">
<h3 class="modal-title"></h3>
</div>
<div class="modal-body">
<h3>{{alert_data.text}}</h3>
</div>
<div class="modal-footer">
<button class="btn btn-warning" type="button" ng-click="okToProceed()">Ok</button>
<button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button>
</div>
example of confirm to be replaced
$scope.discardSource = function(currentIndex) {
if (confirm("Press 'OK' to confirm.")) {
$log.debug("discardDataSource currentIndex: " + currentIndex);
$log.debug($scope.model.dataSamples[currentIndex]);

Directive inside $modal window throws "undefined is not a function"

Using ui-bootstrap I have a really simple custom directive that lists alerts at the top of the page. On normal pages it works like a champ. When I use my directive inside a $modal popup I get "undefined is not a function" at ngRepeatAction.
The directive I have behind the modal on the main page still works. I can see it behind the modal. It's just the one in the modal popup that breaks. What am I doing wrong?
Modal open code:
$modal.open({
templateUrl: 'partials/main/servers/serverAuths/edit.html',
controller: function($scope, $modalInstance) {
$scope.auth = angular.copy(auth);
$scope.auth.password = null;
$scope.saveAuth = function() {
Auths.editAuth($scope.auth).then(
function(resp) {
if (resp.rc===0) {
Alerts.addAlert('success', 'Auth `'+$scope.auth.name+'` saved.');
_.extend(auth, $scope.auth);
$modalInstance.close();
} else {
Alerts.addAlert('danger', 'Auth `'+$scope.auth.name+'` could not be saved. ' + resp.message, 'serverAuths');
}
}
);
};
$scope.resetAuth = function() {
$modalInstance.close();
};
}
}).result.then(
function() {
Auths.getAuthList().then(
function(resp) {
$scope.auths = resp;
}
);
}
);
Directive template:
<div class="alert-wrapper alert-{{ alert.type }}"
ng-repeat="alert in alerts"
ng-class="{ 'relative':relative }">
<div class="container">
<div alert type="alert.type" close="closeAlert($index)">{{alert.msg}}</div>
</div>
</div>
Directive code:
angular.module('app')
.directive('appAlerts', function() {
return {
restrict: 'A',
replace: true,
scope: {
watchForm: '=',
relative: '#'
},
templateUrl: 'partials/directives/appAlerts.html',
controller: function($scope, Alerts) {
$scope.closeAlert = function(idx) { Alerts.closeAlert(idx); };
$scope.alerts = Alerts.getAlerts();
}
};
});
Alerts Factory:
angular.module('app').factory('Alerts', function($timeout) {
var alerts = [];
function timeoutAlert(a) {
$timeout(function() {
a.splice(0, 1);
}, 2500);
}
var addAlert = function(type, msg) {
alerts.push({type:type, msg:msg});
timeoutAlert(alerts);
};
var closeAlert = function(index) {
alerts.splice(index, 1);
};
var getAlerts = function() {
return alerts;
};
var killAlert = function(msg) {
var alert = _.where(alerts, {msg:msg});
var idx = _.indexOf(alerts, alert[0]);
if (idx > -1) {
closeAlert(idx);
}
};
return {
addAlert:addAlert,
closeAlert:closeAlert,
getAlerts:getAlerts,
killAlert:killAlert
};
});

Resources