Open modal on eventClick function in full calendar angular 1.x - javascript

In full calendar, when I click on an event, I want a modal to pop up. I have the modal code and I am referencing through a $scope variable in my directive but nothing is happening.
I am pretty lost and cannot find a good example to work off of. could anyone suggest anything?
At the very least, I want the modal to at least open on the screen, even if its empty, but I don't understand how to do that.
Calendar config:
myApp.directive('msResourceCalendarDirective', function ($window, $timeout, $http) {
return {
restrict: 'AE',
templateUrl: '/client/resourceCalendarDirective/view.html?v=1',
controller: function($scope, $element, $attrs, $uibModal) {
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
// Open modal from modal
$scope.alertOnEventClick = function (eventObj) {
console.log('Opening modal...');
var modalInstance = $uibModal.open({
animation: true,
templateUrl: 'resourceUpdateEventCalendar/view.html',
backdrop: false,
resolve: {
event: function () {
return eventObj;
}
}
});
// Scope apply here to make modal show up
$scope.$evalAsync(function() {
modalInstance.result.then(
function (event) {
console.log('Modal closed at: ' + new Date());
console.log(event);
//$scope.events.push(event);
},
function () {
console.log('Modal dismissed at: ' + new Date());
}
);
});
};
// empty array of events
$scope.events = [];
$scope.myevents = function(start, end, timezone, callback) {
$http.get('/api/v1/sample').then(function(response) {
//var events = [];
angular.forEach(response.data, function(event,key){
$scope.events.push({
id: event._id,
title: event.title,
start: event.startDateTime,
end: event.endDateTime
});
});
callback($scope.events);
});
};
/* config calendar object */
$scope.uiConfig = {
calendar: {
height: 650,
editable: true,
header: {
left: 'month basicWeek basicDay',
center: 'title',
right: 'today prev, next'
},
eventClick: $scope.alertOnEventClick
// eventDrop: $scope.alertOnDrop,
// eventResize: $scope.alertOnSize
}
};
// linking event array to calendar to be displayed
$scope.eventSources = [$scope.myevents];
}
}
});
resourceUpdateEventCalendar/view.html
<!-- Update Modal -->
<div class="modal" id="calendarModal" >
<div class="modal-dialog">
<div class="modal-content" >
<div class="modal-header">
<h3>Edit Resource</h3>
</div>
<div class="modal-body">
<div class="form-group row">
<div class="col-xs-6">
<label for="resourceTitle">Title</label>
<input id="resourceTitle" class="form-control" type="text" name="title" ng-model="sample.title">
</div>
</div>
<div class="form-group">
<ms-date-time-picker ng-model="sample.startDateTime" placeholder="From" id="dateFrom"></ms-date-time-picker>
</div>
<div class="form-group">
<ms-date-time-picker ng-model="sample.endDateTime" placeholder="To" id="dateTo"></ms-date-time-picker>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="updateResource()" >Update Resource</button>
<button class="btn btn-danger" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
EDIT: ok, after hours of research, I realized that recent AngularJS version supports $uibModal , which I wasn't using previously. I have changed my code around but I am still getting errors in console log:
[Error] Failed to load resource: the server responded with a status of 404 (Not Found) (view.html, line 0)
Error: [$compile:tpload] http://errors.angularjs.org/1.6.2/$compile/tpload?p0=resourceUpdateEventCalendar%2Fview.html&p1=404&p2=Not%20Found
http://localhost:3000/libs/angular/angular.min.js?1.6.4:6:430
http://localhost:3000/libs/angular/angular.min.js?1.6.4:159:188
http://localhost:3000/libs/angular/angular.min.js?1.6.4:134:168
$digest#http://localhost:3000/libs/angular/angular.min.js?1.6.4:145:97
$apply#http://localhost:3000/libs/angular/angular.min.js?1.6.4:148:348
l#http://localhost:3000/libs/angular/angular.min.js?1.6.4:101:95
onload#http://localhost:3000/libs/angular/angular.min.js?1.6.4:106:490
Error: [$compile:tpload] http://errors.angularjs.org/1.6.2/$compile/tpload?p0=resourceUpdateEventCalendar[object Object]view.html&p1=404&p2=Not%6Found
http://localhost:3000/libs/angular/angular.min.js?1.6.4:6:430
http://localhost:3000/libs/angular/angular.min.js?1.6.4:159:188
http://localhost:3000/libs/angular/angular.min.js?1.6.4:134:168
$digest#http://localhost:3000/libs/angular/angular.min.js?1.6.4:145:97
$apply#http://localhost:3000/libs/angular/angular.min.js?1.6.4:148:348
l#http://localhost:3000/libs/angular/angular.min.js?1.6.4:101:95
onload#http://localhost:3000/libs/angular/angular.min.js?1.6.4:106:490
At this point, I am lost for a solution..has anyone experienced anything similar to this?

I found the solution. I was missing a parent directory path name in templateURL. the file is nested in a folder called client
templateUrl: 'resourceUpdateEventCalendar/view.html'
should have been
templateUrl: 'client/resourceUpdateEventCalendar/view.html'
I hope this can help someone who is facing a similar issue

Related

Watch window clicks if terms and conditions not accepted

Right on the first user login to my app I display a terms and conditions pop up. It can be easily closed in Dev Tools and the app can be freely used. How can I possible watch a sessionStorage variable requireTerms? requireTerms changes from true to false depending on whether the terms and conditions have been accepted.
I want to detect a click if the modal has been closed in html editor and re-open pop-up again.
Is there an AngularJS way of setting up a config to do that?
I've got this function in one of my services
var service = this;
service.showTerms = function() {
$uibModal.open({
templateUrl: 'app/terms/terms.html',
controller: 'tsAndCs as vm',
size: 'md',
backdrop: false,
keyboard: false
}).result.then(function(response) {
}, function() {
});
};
so I can basically call appState.showTerms(); however I am trying to figure out how to detect that window has been forced to be closed and call the function.
#edit
I thought of having a variable requireTermsOpened (which will be set to false only when user actually clicks on 'Accept') when the modal is displayed and writing something like
var requireTerms = sessionStorage.getItem('requireTerms');
var requireTermsOpened = sessionStorage.getItem('requireTermsOpened');
if(requireTerms && requireTermsOpened) {
appState.showTerms();
}
$uibModal.open({
templateUrl: 'app/terms/terms.html',
controller: 'tsAndCs as vm',
size: 'md',
backdrop: false,
keyboard: false
}).result.then(function(response) {
})
.catch(function() {
// Here you can add your code, its the event that gets called when the modal is dimissed
});
Please test it, I am quite sure it will help you, sorry if its bad formatted, I believe you got the idea, right?
You can try something like the below code. Also check this plunker for your given example scenario.
Controller:
$scope.modelFn = function() {
var modalInstance = $uibModal.open({
templateUrl: 'confirmationWindow.html',
windowClass: 'modal',
controller: function ($scope, $uibModalInstance) {
$scope.confirm = function(userAgreement) {
$uibModalInstance.close(userAgreement);
};
$scope.cancel = function() {
$uibModalInstance.dismiss('cancel');
};
},
size: 'md',
backdrop: false,
keyboard: false
});
modalInstance.result.then(function(selectedItem) {
if (selectedItem) {
alert('Selected check box and clicked OK!');
}else{
alert('Clicked OK Button without Selecting Checkbox!');
}
}, function() {
alert('Clicked Cancel button or Considered cancel on click of outside the Model popup window!');
});
};
Template:
<div ng-controller="MainCtrl">
<script type="text/ng-template" id="confirmationWindow.html">
<div class="modal-header">
<h3 class="modal-title">Terms & Conditions</h3>
</div>
<div class="modal-body">
<p>...........</p>
<p>
<input type="checkbox" ng-model="userAgreement"/>
Are you agreed with all terms and conditions?</p>
</div>
<div class="modal-footer">
<button class="btn btn-warning" ng-click="confirm(userAgreement)">Confirm</button>
<button class="btn btn-default" ng-click="cancel()">Cancel</button>
</div>
</script>
<button class="btn" ng-click="modelFn()">Open Modal</button>
</div>

AngularJS Bootstrap modal freezes on full calendar event onclick

I have a very strange error. Whenever I click an event on my full calendar, a modal is supposed to appear except, it freezes the entire page before opening up.
frozen modal
in the link above, the thin grey line at the top is the modal.
Bootstrap Modal popping up but has a "tinted" page and can't interact
I tried the following solution but it did not seem to make a difference in my case. Can anyone suggest a fix/faced a similar issue before?
directive.js
myApp.directive('msResourceCalendarDirective', function ($window, $timeout, $http) {
return {
restrict: 'AE',
templateUrl: '/client/resourceCalendarDirective/view.html?v=1',
controller: function($scope, $element, $attrs, $uibModal) {
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
// Open modal from modal
$scope.alertOnEventClick = function (eventObj) {
console.log('Opening modal...');
var modalInstance = $uibModal.open({
animation: true,
templateUrl: '/client/resourceCalendarDirective/modal.html',
backdrop: false,
keyboard: true,
resolve: {
event: function () {
return eventObj;
}
}
});
// Scope apply here to make modal show up
$scope.$evalAsync(function() {
modalInstance.result.then(
function (event) {
console.log('Modal closed at: ' + new Date());
console.log(event);
//$scope.events.push(event);
},
function () {
console.log('Modal dismissed at: ' + new Date());
}
);
});
};
// empty array of events
$scope.events = [];
$scope.myevents = function(start, end, timezone, callback) {
$http.get('/api/v1/sample').then(function(response) {
//var events = [];
angular.forEach(response.data, function(event,key){
$scope.events.push({
id: event._id,
title: event.title,
start: event.startDateTime,
end: event.endDateTime
});
});
callback($scope.events);
});
};
/* config calendar object */
$scope.uiConfig = {
calendar: {
height: 650,
editable: true,
header: {
left: 'month basicWeek basicDay',
center: 'title',
right: 'today prev, next'
},
eventClick: $scope.alertOnEventClick
// eventDrop: $scope.alertOnDrop,
// eventResize: $scope.alertOnSize
}
};
// linking event array to calendar to be displayed
$scope.eventSources = [$scope.myevents];
}
}
});
modal.html
<!-- Update Modal -->
<div class="modal" id="calendarModal.html" >
<div class="modal-dialog">
<div class="modal-content" >
<div class="modal-header">
<h3>Edit Resource</h3>
</div>
<div class="modal-body">
<div class="form-group row">
<div class="col-xs-6">
<label for="resourceTitle">Title</label>
<input id="resourceTitle" class="form-control" type="text" name="title" ng-model="sample.title">
</div>
</div>
<div class="form-group">
<ms-date-time-picker ng-model="sample.startDateTime" placeholder="From" id="dateFrom"></ms-date-time-picker>
</div>
<div class="form-group">
<ms-date-time-picker ng-model="sample.endDateTime" placeholder="To" id="dateTo"></ms-date-time-picker>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="updateResource()" >Update Resource</button>
<button class="btn btn-danger" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
Maybe you should try to increase z-index property of modal?
Try
<div class="modal-dialog" id="my-modal">
And then from resolve:
event: function () {
return eventObj;
}
showModal: () {
setTimeout(function () {
$('#my-modal').parent().css('z-index', '10000')
}, 5000);
}
Dirty solution, but may be a solution in your case. Timeout is added to allow everything to render (#my-modal) has to be initialized and visible.

What is the best way to call a method in a controller from a service in angular?

I've done some research on this question both in SO and on Google as well. But none of the answers serve my purpose.
I have a modal in an HTML view, which I use to show popup notifications in my app.
I want to show some buttons ('OK', 'Cancel', 'Login', etc.,) in a div on modal which I pass dynamically as a JS object. Name of the button being the key and the callback function being the value.
Examples:
{
"Login": function(){....}
}
{
"OK": function(){...},
"Cancel": function(){...}
}
Now I pass this kind of objects to a method showPopup(message, buttonMap) in the controller of the popup modal I have in view.
message being the display message on the popup and buttonMap being the object in examples.
Controller:
angular.module('core').controller('PopupController', ['$rootScope', 'LogService', 'MessageHandlerService',
function ($rootScope, LogService, MessageHandlerService) {
var ctrl = this;
ctrl.buttonMap = {};
ctrl.btnWidth = 100;
$rootScope.$on('popup', showPopup);
function showPopup (event, message, buttonMap) {
$('#genericModalDialog .popup-content p').html(message);
ctrl.buttonMap = buttonMap;
var numberOfButtons = Object.keys(buttonMap).length;
ctrl.btnWidth = (100 - numberOfButtons*2)/numberOfButtons;
$("#genericModalDialog").modal('show');
}
ctrl.callbackFor = function callbackFor(key) {
ctrl.buttonMap[key].call(null);
};
}
]);
Service:
angular.module('core').service('PopupService', ['$rootScope', 'LogService', 'CacheService', 'MessageHandlerService',
function ($rootScope, LogService) {
this.isPopupShown = function (){
return $("#genericModalDialog").hasClass('in');
}
this.showPopup = function (message, btnMap){
$rootScope.$broadcast('popup', message, btnMap);
}
this.closePopup = function (){
$("#genericModalDialog").modal('hide');
}
}
]);
View:
<div ng-controller="PopupController as popupCtrl" class="modal fade" id="genericModalDialog" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="vertical-alignment-helper">
<div class="modal-dialog vertical-align-center" style="width:94%;">
<div class="modal-content">
<div class="modal-body">
<br/><br/>
<div class="popup-content">
<p align="center"></p><br/>
<div class="popup-action">
<button type="button" class="btn" style="width:{{popupCtrl.btnWidth}}%; margin:1%" ng-repeat="(buttonName, callBack) in popupCtrl.buttonMap" ng-click="popupCtrl.callbackFor(buttonName)">{{buttonName}}</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Since I don't want to instantiate PopupController in every other controller/service, I've written a service called PopupService which has a method that can called and will $broadcast an event called "popup" on $rootscope and I am handling this event in PopupController. Everything is triggered and working properly in this case. The only problem I face is the delay in rendering the popup on the UI, I see the message as soon as the popup is displayed but the rendering of buttons is very slow (approx 3 secs) this is because of loading of some other web page in the background.
When I searched about the issue on the internet I also found this total setup can be changed to a directive and the rendering of dynamic content (in this case the popup and buttons on it.) could be placed in a link function of the directive.
Another approach I saw was directly handling the DOM manipulation in the service which of course is not a good way.
Did I miss any other approach or a solution to this issue?
All I want to know is what would the best way be, to handling this situation which is programmatically and design wise good.
If I am not clear please let me know. I'll try explaining the problem again.
Directive would be a much better choice that the DOM manipulation. Additionally you should consider changing the usage of jQuery dialog into a https://angular-ui.github.io/bootstrap/#/modal.
Here is an example how it can be done:
1) Create the directive
app.directive('myModal', function() {
return {
restrict: 'E',
scope: {
items: "=",
message: "="
},
replace: true,
templateUrl: "directiveTemplate.html",
controller: function($scope, $uibModal, $log) {
$scope.open = function(size) {
var modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: size,
resolve: {
items: function() {
return $scope.items;
},
message: function() {
return $scope.message;
}
}
});
modalInstance.result.then(function(selectedItem) {
$scope.button = selectedItem.name;
$scope[selectedItem.callback](selectedItem.name);
});
};
}
}
});
2) Create modalInstance directive
app.controller('ModalInstanceCtrl', function($scope, $uibModalInstance, items, message) {
$scope.items = items;
$scope.message = message;
$scope.close = function(item) {
$uibModalInstance.close(item);
};
});
3) create directive template directiveTemplate.html
<div>
{{buttonClicked}}
<br> {{button}}
<button type="button" class="btn btn-default" ng-click="open('sm')">{{message}}</button>
</div>
4) create popup template 'myModalContent.html'
{{message}}
<button ng-repeat="item in items" type="button" class="btn btn-default" ng-click="close(item)">{{item.name}}</button>
5) define you controller where you will have list of buttons and message to be displayed in the popup (for demo purpose here are two different list of items and two messages)
app.controller('ModalDemoCtrl', function($scope) {
$scope.message = "modal 1";
$scope.items = [{
name: 'item1',
callback: "test1"
}, {
name: 'item2',
callback: "test2"
}, {
name: 'item3',
callback: "test3"
}];
$scope.message2 = "modal 12222";
$scope.items2 = [{
name: 'item1222',
callback: "test1"
}, {
name: 'item2222',
callback: "test2"
}, {
name: 'item3222',
callback: "test3"
}];
$scope.test1 = function(message) {
$scope.buttonClicked = "clicked test1";
}
$scope.test2 = function(message) {
$scope.buttonClicked = "clicked test2";
}
$scope.test3 = function(message) {
$scope.buttonClicked = "clicked test3";
}
});
and in order to you the directive you need:
<div ng-controller="ModalDemoCtrl">
<my-modal items="items" message="message"></my-modal>
</br>
<my-modal items="items2" message="message2"></my-modal>
</div>
If you have directive accessed from different angular application instances, than just inject directive application into the needed one (make sure the directive and modal instance to have a their own defined module ex: var app = angular.module('myPopupDynamicModule', ['ngAnimate', 'ui.bootstrap']); and this is the one to be used for injection into other modules following this example: var app2 = angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap', 'myPopupDynamicModule']);)

Angular Modal not binding to scope properties

I have a model controller like such:
pcApp.controller("ModalInstanceController", function ($scope, $modalInstance, model) {
$scope.claim = model;
$scope.payNow = function () {
$modalInstance.close("now");
};
$scope.refuse = function () {
$modalInstance.close("later");
};
$scope.payLater = function () {
$modalInstance.dismiss("cancel");
};
});
The modal template is:
<script type="text/ng-template" id="newClaimPopup.html">
<div class="modal-header">
<h3 class="desktop">PayCaddy Claim</h3>
</div>
<div class="modal-body">
<p>{{claim.SenderFullName}} is claiming an amount of R{{claim.Amount}} for a golfing bet with him that you lost, with the message:</p>
<br />
<p>{{claim.Description}}</p>
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" ng-click="payNow()">Yes</button>
<button class="btn btn-danger" type="button" ng-click="refuse()">Refuse</button>
<button class="btn btn-warning" type="button" ng-click="payLater()">Later</button>
</div>
</script>
This is in a partial view included in _Layout.cshtml:
<div id="claim-notice-template">
#Html.Partial("_NewClaimPopupTemplate")
</div>
I show the modal using this code:
$scope.showNewClaimPopup = function (viewModel) {
$scope.claim = viewModel;
var modalInstance = $modal.open({
animation: $scope.animationsEnabled,
templateUrl: "newClaimPopup.html",
controller: "ModalInstanceController",
size: "sm",
resolve: {
model: function () {
return $scope.claim;
}
}
});
modalInstance.result.then(function () {
debugger;
$log.info("Modal accepted at: " + new Date());
}, function () {
$log.info("Modal dismissed at: " + new Date());
});
};
The viewModel parameter passed in to $scope.showNewClaimPopup is valid and fully populated. The resolve option for open is also working, because in ModalInstanceController I can see that the model parameter is the same valid viewmodel. Yet when the modal displays, the binding templates are all blank.
All code shown is in one MainController assigned to a div that surrounds everything, including the partial containing the modal template.
Why is the template not binding as expected?
You need to pass $scope to be used to compile modal template:
var modalInstance = $modal.open({
scope: $scope, // <--- this line is necessary
animation: $scope.animationsEnabled,
templateUrl: "newClaimPopup.html",
controller: "ModalInstanceController",
size: "sm",
resolve: {
model: function () {
return $scope.claim;
}
}
});
If you don't provide scope config then modal will create new child scope of the $rootScope, which obviously doesn't contain claim object.

Bootstrap/Angular modal no longer works after opening and closing once

I have a page which opens a modal that asks for user confirmation when making an edit to something on the page. If the user chooses "Cancel" button in the modal, the modal closes fine, but then refuses to re-open with the same link. The following error gets thrown if the modal link is clicked again:
TypeError: fn is not a function
at $parseFunctionCall (https://localhost:44310/js/angular.js:12346:15)
at ngEventDirectives.(anonymous function).compile.element.on.callback (https://localhost:44310/js/angular.js:21438:17)
at Scope.$get.Scope.$eval (https://localhost:44310/js/angular.js:14401:28)
at Scope.$get.Scope.$apply (https://localhost:44310/js/angular.js:14500:23)
at HTMLAnchorElement.<anonymous> (https://localhost:44310/js/angular.js:21443:23)
at HTMLAnchorElement.n.event.dispatch (https://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.4.min.js:3:6466)
at HTMLAnchorElement.n.event.add.r.handle (https://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.4.min.js:3:3241)
Here is the controller for the modal, very simple:
(function (angular, undefined) {
"use strict";
angular
.module("app.edit")
.controller("App.EditController", [
"$modalInstance", "$scope", "editList",
function ($modalInstance, $scope, editList) {
$scope.thingsToEdit = editList;
$scope.ok = function () {
$modalInstance.close();
};
$scope.cancel = function () {
$modalInstance.dismiss("cancel");
};
}
]);
})(angular);
The editList is used to display a list in the confirmation modal, the html of the page.
And the HTML for the modal is:
<div class="modal-header">
<h3>Edit</h3>
</div>
<div class="modal-body">
<p>Please confirm the following edits: </p>
<ul>
<li ng-repeat="thing in thingsToEdit">{{thing}}</li>
</ul>
</div>
<div class="modal-footer">
<div class="form">
<div class="form-group">
<button class="btn btn-primary" type="submit" ng-click="ok()">Confirm Edit</button>
<button class="btn btn-danger" ng-click="cancel()">Cancel</button>
</div>
</div>
</div>
And in the JavaScript for the original page that opens the modal is:
$scope.edit = function (things) {
$scope.editList = things;
$scope.thingsToEdit = things;
var editModal = $modal.open({
animation: true,
templateUrl: "edit.html",
controller: "App.EditController",
resolve: {
editList: function () {
return $scope.thingsToEdit;
}
}
});
editModal.result.then(function () {
var editUrl = //a valid url
$http.post(editUrl, { cache: true })
.success(function () {
console.log("edit successful");
})
.error(function () {
console.log("edit failed");
})
}, function() {
console.log("edit canceled");
});
};

Categories

Resources