ng-repeat producing unexpected and strange results - angularjs

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);
}
});

Related

how to use recursive function to select the parent in a tree array using angulat ui tree?

So, I'm trying to create a hierarchical tree. Whena node is selected that has children, then all the children of the node is selected, but when I select all the children I also want to select the parent.
here is a link to the plunker:
[https://plnkr.co/plunk/iMBFfy6cf7urOHhZ][1]
I have created a directory to markup the tree
TreeController.js
(function (ng) {
var app = ng.module('tree', ['tree.service', 'tree.directives']);
app.controller("TreeController", ["TreeService", "$scope", function (TreeService, $scope) {
var tc = this;
buildTree();
function buildTree() {
TreeService.getTree().then(function (result) {
tc.tree = result.data;
}, function (result) {
alert("Tree no available, Error: " + result);
});
}
$scope.selectedItems = [];
$scope.getSelected = function(){
$scope.selectedItems = [];
function checkChildren(c) {
angular.forEach(c.children, function (c) {
if (c.checked){
$scope.selectedItems.push({"selected":c.name});
}
checkChildren(c);
});
}
angular.forEach(tc.tree, function(value, key) {
if (value.checked){
$scope.selectedItems.push({"selected":value.name});
}
checkChildren(value);
});
};
}]);
})(angular);
index.html
<div ng-controller="TreeController as tc">
<ul class="tree">
<node-tree children="tc.tree"></node-tree>
</ul>
<button ng-click="getSelected()">Get Selected</button>
<br/>
<br/>
Selected:
<ul>
<li ng-repeat="item in selectedItems">
{{item.selected}}
</li>
</ul>
</div>
TreeDirective.js
(function (ng) {
var app = ng.module('tree.directives', []);
app.directive('nodeTree', function () {
return {
template: '<node ng-repeat="node in tree"></node>',
replace: true,
restrict: 'E',
scope: {
tree: '=children'
}
};
});
app.directive('node', function ($compile) {
return {
restrict: 'E',
replace: true,
templateUrl: 'node.html', // HTML for a single node.
link: function (scope, element) {
/*
* Here we are checking that if current node has children then compiling/rendering children.
* */
if (scope.node && scope.node.children && scope.node.children.length > 0) {
scope.node.childrenVisibility = true;
var childNode = $compile('<ul class="tree" ng-if="!node.childrenVisibility"><node-tree children="node.children"></node-tree></ul>')(scope);
element.append(childNode);
} else {
scope.node.childrenVisibility = false;
}
},
controller: ["$scope", function ($scope) {
// This function is for just toggle the visibility of children
$scope.toggleVisibility = function (node) {
if (node.children) {
node.childrenVisibility = !node.childrenVisibility;
}
};
// Here We are marking check/un-check all the nodes.
$scope.checkNode = function (node) {
node.checked = !node.checked;
// if (node.checked){
// alert("clicked");
// }
function checkChildren(c) {
angular.forEach(c.children, function (c) {
c.checked = node.checked;
checkChildren(c);
});
}
checkChildren(node);
};
}]
};
});
})(angular);
node.html
<li>
<span ng-click="toggleVisibility(node)"> {{ ( node.childrenVisibility && node.children.length ) ? '+' : '-' }}</span>
<input ng-click="checkNode(node)" type="checkbox" ng-checked="node.checked">
<span>
{{ $index + 1 }}. {{ node.name }}
</span>
</li>
The first step is to determine what each node's parent node is. We can do that by recursing right after the tree is loaded and setting a parent property on each node.
TreeController.js
...
function buildTree() {
TreeService.getTree().then(function (result) {
tc.tree = result.data;
function setParentForChildren(n) {
angular.forEach(n.children, function (c) {
c.parent = n;
setParentForChildren(c);
})
}
angular.forEach(tc.tree, setParentForChildren);
}, function (result) {
alert("Tree no available, Error: " + result);
});
}
...
Now, we can use that parent reference each time a box is checked to recurse up the tree and say "if all my children are checked, then I should be checked too" for each parent node.
TreeDirective.js
...
$scope.checkNode = function (node) {
node.checked = !node.checked;
function checkParent(n) {
if (!n.parent)
return;
const p = n.parent;
p.checked = p.children.every(function(c) { return c.checked });
checkParent(p);
}
checkParent(node);
function checkChildren(c) {
angular.forEach(c.children, function (c) {
c.checked = node.checked;
checkChildren(c);
});
}
checkChildren(node);
};
...
Link to modified plunker

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-click does not work in directive of inline magnific popup

I have created magnific popup directive in angularjs. It works fine ng-click event on description link when first time loads but after close popup and again click on description link it does not work.
Please refer below code:
PhotoCtrl.js
(function () {
'use strict';
function PhotoCtrl($rootScope, $scope, $state, HzServices, HzPhotoService) {
$scope.doAlbumList = function () {
var data = {q: $state.params.pid};
$scope.albums = {};
$scope.albumsCount = 0;
$scope.photos = {};
$scope.photosCount = 0;
$rootScope.arrData = [];
var deferred = HzServices.deferred("/api/album/list", 'GET', data);
deferred.then(
function (res) {
/*
* success in repsonse
* Share common photo & album data across all controllers, directives by services.
*/
var data = {album: {count: res.data.count.album, data: res.data.album}, photo: {count: res.data.count.photo, data: res.data.photo}};
/*
* Create an array of magnific inline popup content
*/
angular.forEach(data.photo.data, function (value, key) {
if (value.data.length > 0) {
angular.forEach(value.data, function (value_, key_) {
$rootScope.arrData.push({
imageDescription: value_.photo_description,
imageScale_img: "/resize/" + value_.module + "/" + value_.photo_name,
imageOriginal_href: "/" + value_.module + "/" + value_.photo_name
});
});
}
});
HzPhotoService.setSharedData(data);
$scope.albums = $rootScope.sharedData.album.data;
$scope.albumsCount = $rootScope.sharedData.album.count;
$scope.photos = $rootScope.sharedData.photo.data;
$scope.photosCount = $rootScope.sharedData.photo.count;
},
function (res) {
/*
* Error hading in repsonse
*/
var data = {album: {count: $scope.albumsCount, data: $scope.albums}, photo: {count: $scope.photosCount, data: $scope.photos}};
HzPhotoService.setSharedData(data);
}
);
}
/**
* Get Photos data & count
* #returns {Array}
*/
$scope.doGetPhoto = function () {
return [{photos: $scope.photos, photoCount: $scope.photoCount}];
}
$scope.doEditDescription = function () {
console.log("description links from controller called");
}
angular
.module("AppWhizbite")
.controller('PhotoCtrl', ['$rootScope', '$scope', '$state', 'HzServices', 'HzPhotoService', PhotoCtrl]);
}());
photoList.html
<div>
<div class="total_album_photo gallery" ng-repeat-start="photo in photos track by $index">
<div class="no_of_photo imgWrapper">
<a href="javascript:void(0);" class="popup-link" data-index="{{$index}}">
<img ng-src="/resize/photo/{{photo.photo_name}}" height="120" width="120"/>
</a>
</div>
</div>
<div ng-repeat-end=""><hz-photo-popup></hz-photo-popup></div>
</div>
hzPhotoDirective.js
(function () {
'use strict';
angular
.module("AppWhizbite")
.directive("hzPhotoPopup", ["$rootScope", "$compile", "HzPhotoService", function ($rootScope, $compile, HzPhotoService) {
var magnificMarkup = "\n\
<form ng-controller=\"PhotoCtrl as Photo\" class=\"white-popup-block popMarkup ng-pristine ng-valid ng-scope\" id=\"dataPopup\" >\n\
<div class=\"popup_heading\">Photo</div>\n\
<div id=\"img_center\">\n\
<img style=\"width:100%\" src=\"\" id=\"img_center_content\" class=\"mfp-imageScale\">\n\
</div>\n\
<div class=\"popup_main\">\n\
<div class=\"popup_left photo_popup_left\">\n\
<div class=\"popup_raw1\">\n\
Edit description\n\
<div class=\"mfp-imageDescription\" style=\"cursor:pointer;\" ng-click=\"doEditDescription()\"></div>\n\
<textarea class=\"submitByEnter commentarea mfp-imageDescription\" placeholder=\"Edit description\" style=\"height: 76px;display:none;\"></textarea>\n\
</div>\n\
</div>\n\
</div>\n\
<div class=\"video_main\">\n\
</div>\n\
<button class=\"mfp-close\" type=\"button\" title=\"Close (Esc)\">×</button>\n\
</form>";
return {
restrict: "AE",
replace: false,
scope: true,
compile: function (scope, element) {
return{
pre: function (scope, element, attrs) {
if (scope.$last) {
// Iterate through all thumbnails class to bind magnific popup plugins
angular.forEach(angular.element(".gallery > .imgWrapper > a"), function (val, key) {
angular.element(".popup-link").eq(key).magnificPopup({
key: 'my-popup',
//items: arrData, // Array of media details
items: $rootScope.arrData, // Array of media details
index: key, // Index of media ref: data-index
type: 'inline',
verticalFit: true, // Fits image in area vertically
inline: {
// Magnific popup custom markup to show media (photo) gallery
markup: $compile(magnificMarkup)(scope)
},
gallery: {
enabled: true
},
callbacks: {
open: function () {
console.log("open called");
},
change: function () {
console.log("cahnge callaed");
},
markupParse: function (template, values, item) {
// optionally apply your own logic - modify "template" element based on data in "values"
// console.log('Parsing:', template, values, item);
console.log("markup parse called");
},
elementParse: function (item) {
console.log("element parse called");
}
}
});
});
}
}
}
},
link: function (scope, element, attrs) {
console.log("link method called");
}
}
}]);
}());
After R&D I crack the issue.
Magnific Popup callbacks objects have markupParse() method. It calls in every action of popup, so I put my angular js template $compile in markupParse method and it works fine.
It may different as per conditions or situations, but almost in all conditions it works finally fine.
Code:
inline: {
// Magnific popup custom markup to show media (photo) gallery
markup: magnificMarkup
},
callbacks:{
markupParse: function (template, values, item) {
$compile(template)(scope);
}
}
In the markupParse method having 3 parameters:
template : template holds actual HTML template which use in popup.
values: value holds current indexed value from arrData
item: item hold current item object.

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

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.

Resources