open multiple modal from one directive simultaneously in angularjs - angularjs

I have a grid-view containing many records and I want this behaviour that when the user double-click on each record, a window-like modal dialogue opens for him to view details about that record, and meanwhile he/she can read other records on the grid-view and maybe double click on another record to open a new window to view selected record details while another window is still open.
my question is very similar to this question I found on StackOverflow
but the accepted answer doesn't seem to work.
this is my effortless project to test this workflow,
app.controller('ModalCtrl', function($scope, $modal) {
$scope.showModal = function() {
$scope.opts = {
templateUrl : 'modalContent.html',
controller : ModalInstanceCtrl,
resolve: {}
};
$scope.opts.resolve.item = function() {
}
var modalInstance = $modal.open($scope.opts);
modalInstance.result.then(function(){
},function(){
console.log("Modal Closed");
});
}; })
but it's created by modal and I know modals are not designed for such behaviour and I would like to know the best solution for such thing,
thanks in advance.

Related

How to persist a success icon in the view after modal function with AngularJS and UI-Bootstrap? (Plunker)

I'm making something that works similarly to this plunker that I created.
In my app I'm using Firebase/AngularFire.
In the plunker you can see that when you check-in to a meeting, the icon changes to a success icon. In my app this is where I store that info in Firebase like this:
$scope.join = function(hash) {
console.log(hash);
var ref = dbRef.ref('meetings/'+hash+'/users')
var meetingInfo = $firebaseArray(ref);
meetingInfo.$add({
date: firebase.database.ServerValue.TIMESTAMP,
user_name: $scope.name,
user: $scope.currentUser
}).then(function(ref) {
var key = ref.key;
var index = meetingInfo.$indexFor(key);
console.log(key, index);
$uibModalInstance.close();
});
};
So the data gets added into Firebase and then the modal closes.
I also have a similar controller and view for listing out the meetings just like in the plunker.
In the plunker I send a variable through $rootScope so it's accessible in the listingController. That works, but as you can see I can only check-in to one meeting, and after I refresh or check-in to another meeting, the check-mark disappears.
I would like to know how to persist this change so that anytime I check-in to a meeting the check-mark will stay. I'm thinking that I need to edit something in my listing controller so that when it grabs the data, it can check to see if someone has checked in to the meeting, and display the checkmark, so here is my Firebase list controller:
app.controller('listController', ['$scope', '$rootScope', '$firebaseArray', '$firebaseObject', '$uibModal', function($scope, $rootScope, $firebaseArray, $firebaseObject, $uibModal) {
var ref = firebase.database().ref('meetings');
var list = $firebaseObject(ref);
list.$loaded().then(function(data) {
$scope.lobbies = list;
});
}]);
EDIT
The way Firebase stores the data is like this:
---meetings
------random hash (key)
---------date
---------name
---------attendees
------------random hash
---------------date
---------------name
When I do my ng-repeat it's like this: ng-repeat="(key, meeting) in meetings" so I can access the meeting data like meeting.name. How should I go about accessing the attendees to check if the current user is in the meeting?
SOLUTION
This question helped me out a lot in addition to the HTML snippet that idan provided
You need to decide where you keep this data and how.
You can, for example, hold a list of attendees in the meeting. Something like:
{
users: {
userid1: {
name: 'Someone'
},
userid2: {
name: 'Someone else'
}
// ...
},
meetings: {
meetingid1: {
location: 'Somewhere',
title: 'Gala',
attendees: {
userid1: true,
userid3: true
// ...
}
}
// ...
}
}
Then you can check if a user attends a meeting to change the button.
Also the ng-if there to change buttons seems too much. You can use ng-class on the button and icon, then you'll have only one button instead of two.
<button class="btn btn-sm" ng-click="open(meeting)" ng-class="user.$id in meeting.attendees ? 'btn-success' : 'btn-primary'">
<i class="fa" ng-class="user.$id in meeting.attendees ? 'fa-check' : 'fa-sign-in'"></i>
</button>
One more thing: strongly recommend to read Angular style guide 1 and Angular style guide 2. Both contain great tips to help you maintain your app easily.

If user 'touches' form inputs on profile & forgets to save: show `POP UP` when they click SideMenu icon

I've tried to come up with some sort of "error checker/validation" for my users IF they forget to Save the edits they made on their profiles.
The user enters the Profile.html state. They start to update some of their info (i.e name, phone number, etc.). INSTEAD of pressing the SAVE CHANGES button they navigate away from the Profile state by clicking the SideMenu icon at the top left of their mobile screen.
Since the form is technically now consider to be "$dirty". I've tried to use this angular property at first but I couldn't really get the results I wanted so I tried my luck with $watch..
ProfileController.js
$rootScope.isFormDirty = false;//global variable 'isFormDirty'->inject in controller.js (toggleLeftSideMenu())
$scope.$watch('updateDriverProfileInfo', function(newValue, oldValue) {//new & oldValue = ng-model when form is 1st 'viewed' is dirty
//http://tutorials.jenkov.com/angularjs/watch-digest-apply.html
if (newValue !== oldValue) {
// console.log("updatingg")
$rootScope.isFormDirty = true;
}
}, true);
Angular docs on $watch
Maybe I should of made a factory or Service for this now that I think about it but at the time I used $rootScope so that I can set a global variable isFormDirty on this controller and use it on the General Controller that holds the Side Menu's logic in this Ionic app.
controller.js (this is where the Controller for the SideMenu is)
$scope.sidemenuIsOpen = false;
$scope.toggleLeftSideMenu = function() {//ng-click from menu.html
$scope.sidemenuIsOpen = !$scope.sidemenuIsOpen;
if ($scope.sidemenuIsOpen && $rootScope.isFormDirty) {
var confirmPopup = $ionicPopup.confirm({
title: 'Changes were not saved',
template: 'Do you want to save your changes?',
});
confirmPopup.then(function(res) {
if (res) {
console.log('Run updateDriverProfile()');
} else {
console.log('Allow user to continue w/o changes');
}
});
}
};
That's basically the gist of my code. It actually "works" but I have identified a pattern and this is where I need your assistance to either suggest a whole different method to accomplish this or perhaps some refactoring tips for this current code.
The Pop up does show when the user clicks on the Side Menu button BUT I don't think it really matters if the form is $dirty or not..
The bigger issue is that the Pop up starts showing regardless if you are trying to leave the profile.html view or any other view for that matter.
When I wrote this code I was under the impression that the Pop up and toggleLeftSideMenu functions would ONLY work on the Profile view since I am "watching" the updateDriverProfileInfo object and I also created that global variable to use between the Menu Controller and Profile Controller.
you need to have a good understanding on ionic Lifecycle, try with any of the below events
$scope.$on('$ionicView.leave', function(){
// Anything you can think of
});
$scope.$on('$ionicView.beforeLeave', function(){
// Anything you can think of
});
$scope.$on('$ionicView.unloaded', function(){
// Anything you can think of
});
find more information here http://www.gajotres.net/understanding-ionic-view-lifecycle/

uibModal with a different URL document

I am having the toughest time figuring out how to get my modal to work.
I have a main application document.
I have my modal code to open a modal with a different document.
When I run the document link by itself it works, but when I try to open it in the modal it doesn't seem to find its controller
angular.js:12314Error: [ng:areq] http://errors.angularjs.org/1.4.1/ng/areq?p0=SimpleCtrl&p1=not[object Object]%function%C%got%undefined
$scope.openPopup2 = function (size, qCode) {
var modalInstance = $uibModal.open({
animation: true,
templateUrl: ('core/media/media.nl?id=11457&c=TSTDRV1365574&h=a2ecbb8c50da60473910&_xt=.html?qcode='
+qCode
+'&productid='
+$scope.siteInformation.productId),
scope: $scope,
controller: SimpleCtrl,
size: size,
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
I have tried to remove "controller: SimpleCtrl,"
and even put it in quotes controller: "SimpleCtrl"
I just get similar errors.
The SimpleCtrl gets referenced from the new document that is supposed to appear.
What am I missing?
Ok, like #Michael Rose's comment I moved it to the main application. I was hoping to just have the page load it itself. I stopped fighting it and put it into the main app and it works now. thanks

implementing external links to a page with angular-scroll and ng-route

So this is is an angularjs app.
I have implemented this angular-scroll api :https://github.com/oblador/angular-scroll, to show a catalog of products, where the content is loaded from db. this catalog has all the subcategories (with its products) and every subcategory has an anchor identified like: anchor+categoryId.
So from the menu , i click a category and it scroll nicely to the correct section.
The problem arise when I need to create some links from other pages of the site, to go to an specific section category inside the catalog. Because I have ng-route, i need to create a new url to redirect to the catalog, and there capture when the content is loaded to do the scroll to the required category.
BUT I have a directive associated with the route of the catalog, that looks for the partials depending on the domain of the client, so to show the correct template i have to use an $http , get the content and replace it in my directive.
Because that I dont know how i can know when the content of the directive is ready to make the call to the scroll... better show some code here :
this is the route that is receiving the call
$routeProvider.
when('/products/category/:categoryId/page/:page/anchor/:anchorId?', {
template:'<product-display-view></product-display-view>',
controller: 'ProductListCtrl',
access: {
authorizedRoles: [USER_ROLES.all]
},
resolve: {
wait : 'waitForIt',
prefetchDataProducts: ['waitForIt','$route','SearchService',
function(waitForIt,$route,SearchService) {
return waitForIt.then(function() {
return SearchService.getProducts($route.current.params.categoryId,$route.current.params.page);
});
}],
prefetchDataCategories:['waitForIt','CategoryService',
function(waitForIt,CategoryService) {
return waitForIt.then(function() {
return CategoryService.getCategories();
});
}]
}
}).
this is the directive product-display
productDirectives.directive('productDisplayView',['$rootScope','$compile','$http','$templateCache' ,'$document',
function($rootScope,$compile, $http, $templateCache,$document){
return {
restrict: 'E',
link: function (scope, element, attrs) {
var templateUrl = 'users/catwizardAngularCore/app/partials/themes/' + scope.app.theme.themeName + '/partials/product-display.html';
$http.get(templateUrl, {cache: $templateCache})
.success(function (templateContent) {
element.replaceWith($compile(templateContent)(scope));
});
/* this doesn't work because the someElement doesn't exist*/
var newHash = 'anchor' + scope.anchorId;
var someElement = angular.element(document.getElementById(newHash));
angular.element(someElement).ready(function () {
$document.scrollToElement(someElement, 200, 2000);
});
}
}]);
There is a duplicate question with the correct answer, but it has not been accepted yet so I am copying the answer here.
The $anchorScroll has to occur after the page has been rendered,
otherwise the anchor doesn't exist. This can be achieved using
$timeout().
$timeout(function() {
$anchorScroll('myAnchor');
});
Credits to Tony

Angular UI Dialog - Closing and Reopening from Dialog causes Background

I am trying to close and reopen a dialog from the actual dialog controller's view. What ends up happening is that after dialog close/open, it won't properly close again. Escape works on some browsers (but the overlay remains) and clicking the background may cause the dialog to close but the overlay will remain (browser dependant).
Question: How can I close/reopen a dialog from a function/button/event on the dialog's controller and that the dialog's close works properly (on escape or clicking background).
The demo below is just a boiled down sample that demonstrates the issue as I will be doing a next/prev and I'd like to close/open on those clicks but am having this issue with not being able to exit the modal.
Here is the online demo: http://plnkr.co/h8djNiSlH6c7d8SNzMmb
Open dialog
Close dialog - works fine except IE (another issue).
Open dialog
Click button inside dialog to close/reopen
Try to close the dialog
Controllers:
function PopupCtrl($scope, $dialog, dialog, item, Utils) {
$scope.items = Utils.getItems();
$scope.item = item;
$scope.reOpen = function (item) {
item = $scope.items[1];
dialog.close();
var d = $dialog.dialog({
dialogFade: true,
backdropClick: true,
dialogOpenClass: 'modal-open',
resolve: {
item: function () {
return angular.copy(item)
}
}
});
d.open('dialog.html', 'PopupCtrl');
};
}
function MainCtrl($scope, $window, $dialog, $location, $timeout, Utils) {
$scope.items = Utils.getItems();
$scope.openDialog = function (item) {
item = $scope.items[0];
var d = $dialog.dialog({
dialogFade: true,
dialogOpenClass: 'modal-open',
resolve: {
item: function () {
return angular.copy(item)
}
}
});
d.open('dialog.html', 'PopupCtrl');
};
}
I've tried this with angular bootstrap v0.2.0 and v.0.3.0 so it is either a bug or there is something I am missing with regards to how I am coding the logic.
This turned out to be an issue with the core dialog directive. Filed a issue and consequent pull request to address:
Details here: https://github.com/angular-ui/bootstrap/pull/381

Resources