Alert and Confirmation dialog box AngularJs - angularjs

I'm trying to implement Alert/Confirmation dialog boxes using the bootstrap modal service in my angular app. I want to make it generic, based on the parameter that I pass to the modal's controller it will either behave as the alert box where the user can just close it on reading the message on the modal and also it can behave like a confirmation dialog where the user should say either 'OK' or 'Cancel' I need to capture the response from the user which I'm able to. Now, the problem here is that i've list of items say in a grid and when ever user wants to delete an item from the list I need to show the confirmation message box and based on the user response I need to either delete the item or leave it if users wishes to leave it in the list, but my item is being deleted first and then the confirmation dialog is showing up, I've tried using the call back but still no use. Please help me if anyone came across this situation.
Method that shows the alert:
$scope.showAlertMessage = function (modalName,commands,callback)
{
var modalOptions = {};
var alertMessageText;
var okBtn;
var cancelBtn;
var autoCloseTimeout;
$scope.modalResp === false;
if (modalName === 'ItemNotEligible')
{
modalOptions['template'] = 'application/Views/ItemNotEligibleAlert.html';
modalOptions['cntrlr'] = 'itemAlertsController';
modalOptions['winClass'] = 'item-alert-win';
alertMessageText = commands.alertMessage.text;
okBtn=true;
cancelBtn = false;
autoCloseTimeout=commands.alertMessage.autoDismissalTimeout;
}
else if (modalName === 'ItemDelete')
{
modalOptions['template'] = 'application/Views/ItemNotEligibleAlert.html';
modalOptions['cntrlr'] = 'itemAlertsController';
modalOptions['winClass'] = 'item-alert-win';
alertMessageText = commands.alertMessage.text;
okBtn = true;
cancelBtn = true;
autoCloseTimeout = commands.alertMessage.autoDismissalTimeout;
}
var params = { alertMessage: alertMessageText};
var modalInstance=$modal.open({
templateUrl: modalOptions.template,
controller: modalOptions.cntrlr,
windowClass: modalOptions.winClass,
resolve: {
modalParams: function () {
return params;
}
}
});
modalInstance.result.then(function (selected) {
$scope.modalResp = selected; //Response from the dialog
});
callback($scope.modalResp);
}
Method where the delete item logic exists and call to show alert method is made
this.voidItem = function (skuid) {
alertMessage.text = 'Are you sure you want to remove <strong>' + itemdata[itmid].split('|')[0] + '</strong> from your list?';
$scope.showAlertMessage('ItemDelete', commands, function (userresp) {
if (userresp === true) {
var lineId = 0;
for (var i = itemListState.length - 1; i >= 0; i--) {
if (parseInt(itemListState[i].item) === itmid && Boolean(itemListState[i].isItemVoid) != true) {
lineId = itemListState[i].Id;
if (lineId != 0) {
break;
}
}
}
poService.DeleteItem(itmid, lineId, function (modal) {
virtualtable = modal;
$scope.itemCount = $scope.itemCount - 1;
$scope.createlist(itmid);
});
}
});
}

The problem is that you are executing the callback instead of chain the method to the result of the promise
modalInstance.result.then(function (selected) {
callback($scope.modalResp); //Once the promise is solved, execute your callback
$scope.modalResp = selected; //Why you need to save the response?
// If the user press cancel o close the dialog the promise will be rejected
}, onUserCancelDialogFn);
A more simple way:
modalInstance.result
.then(callback, onErrBack);

Related

angular push result to controller

(was not sure what to have as a title, so if you have a better suggestion, feel free to come up with one - I will correct)
I am working on an angular application where I have some menues and a search result list. I also have a document view area.
You can sort of say that the application behaves like an e-mail application.
I have a few controllers:
DateCtrl: creates a list of dates so the users can choose which dates they want to see posts from.
SourceCtrl: Creates a list of sources so the user can choose from which sources he/she wants to see posts from.
ListCtrl: The controller populating the list. The data comes from an elastic search index. The list is updated every 10-30 seconds (trying to find the best interval) by using the $interval service.
What I have tried
Sources: I have tried to make this a filter, but a user clicks two checkboxes the list is not sorted by date, but on which checkbox the user clicked first.
If it is possible to make this work as a filter, I'd rather continue doing that.
The current code is like this, it does not do what I want:
.filter("bureauFilter", function(filterService) {
return function(input) {
var selectedFilter = filterService.getFilters();
if (selectedFilter.length === 0) {
return input;
}
var out = [];
if (selectedFilter) {
for (var f = 0; f < selectedFilter.length; f++) {
for (var i = 0; i < input.length; i++) {
var myDate = input[i]._source.versioncreated;
var changedDate = dateFromString(myDate);
input[i]._source.sort = new Date(changedDate).getTime();
if (input[i]._source.copyrightholder === selectedFilter[f]) {
out.push(input[i]);
}
}
}
// return out;
// we need to sort the out array
var returnArray = out.sort(function(a,b) {
return new Date(b.versioncreated).getTime() - new Date(a.versioncreated).getTime();
});
return returnArray;
} else {
return input;
}
}
})
Date: I have found it in production that this cannot be used as a filter. The list of posts shows the latest 1000 posts, which is only a third of all posts arriving each day. So this has to be changed to a date-search.
I am trying something like this:
.service('elasticService', ['es', 'searchService', function (es, searchService) {
var esSearch = function (searchService) {
if (searchService.field === "versioncreated") {
// doing some code
} else {
// doing some other type of search
}
and a search service:
.service('searchService', function () {
var selectedField = "";
var selectedValue = "";
var setFieldAndValue = function (field, value) {
selectedField = field;
selectedValue = value;
};
var getFieldAndValue = function () {
return {
"field": selectedField,
"value": selectedValue
}
};
return {
setFieldAndValue: setFieldAndValue,
getFieldAndValue: getFieldAndValue
};
})
What I want to achieve is this:
When no dates or sources are clicked the whole list shall be shown.
When Source or Date are clicked it shall get the posts based on these selections.
I cannot use filter on Date as the application receives some 3000 posts a day and so I have to query elastic search to get the posts for the selected date.
Up until now I have put the elastic-search in the listController, but I am now refactoring so the es-search happens in a service. This so the listController will receive the correct post based on the selections the user has done.
Question is: What is the best pattern or method to use when trying to achieve this?
Where your data is coming from is pretty irrelevant, it's for you to do the hook up with your data source.
With regards to how to render a list:
The view would be:
<div ng-controller='MyController as myCtrl'>
<form>
<input name='searchText' ng-model='myCtrl.searchText'>
</form>
<ul>
<li ng-repeat='item in myCtrl.list | filter:myCtrl.searchText' ng-bind='item'></li>
</ul>
<button ng-click='myCtrl.doSomethingOnClick()'>
</div>
controller would be:
myApp.controller('MyController', ['ElasticSearchService',function(ElasticSearchService) {
var self = this;
self.searchText = '';
ElasticSearchService.getInitialList().then(function(list) {
self.list = list;
});
self.doSomethingOnClick = function() {
ElasticSearchService.updateList(self.searchText).then(function(list) {
self.list = list;
});
}
}]);
service would be:
myApp.service('ElasticSearchService', ['$q', function($q) {
var obj = {};
obj.getInitialList = function() {
var defer = $q.defer();
// do some elastic search stuff here
// on success
defer.resolve(esdata);
// on failure
defer.reject();
return defer.promise();
};
obj.updateList = function(param) {
var defer = $q.defer();
// do some elastic search stuff here
// on success
defer.resolve(esdata);
// on failure
defer.reject();
return defer.promise();
};
return obj;
}]);
This code has NOT been tested but gives you an outline of how you should approach this. $q is used because promises allow things to be dealt with asynchronously.

AngularJS 1.4.1 ng-submit not firing after form reset

I know there are a few older questions with related topics, but I have not found a satisfactory answer to this, plus those answers seem to be for older versions of Angularjs.
My issue is a form with angular validation and ng-submit does not fire after it has been submitted once, even after the model data has been reset, and the form has been untouched and set to pristine.
After the first submission, the form resets visually as expected and validates properly if used a second time, including activating the submit button when validation passes. Comparing the form code before any submissions and after reset produces identical HTML. Clicking submit brings up the preloader as designed. However the ng-submit action won't fire...
$scope.resetMediaForm = function() {
$scope.uploadMedia = {};
$scope.uploadMedia.from = ''
$scope.uploadMedia.message = ''
$scope.uploadMedia.file = null;
$scope.uploadMedia.fileType = '';
$scope.uploadMedia.fileName = '';
$scope.uploadMedia.done = false;
$scope.uploadMedia.error = '';
if ($scope.mediaForm) {
$scope.mediaForm.$setUntouched();
$scope.mediaForm.$setPristine();
//$('form[name="'+$scope.mediaForm.$name+'"]')[0].reset();
}
};
$scope.resetMediaForm();
$scope.uploadMedia.submit = function() {
var data = {
from: $scope.uploadMedia.from,
message: $scope.uploadMedia.message,
file: $scope.uploadMedia.file,
fileType: $scope.uploadMedia.fileType,
fileName: $scope.uploadMedia.fileName
};
plotRemoteAPI.postMedia(data, function (data, status) {
if (status >= 200 && status < 300) {
if (data.success === true) {
$scope.resetMediaForm();
} else {
$scope.uploadMedia.error = data.error;
}
} else {
$scope.uploadMedia.error = status;
}
}, function (data, status) {
$scope.uploadMedia.error = data.error;
});
};
Plunkr: http://embed.plnkr.co/zO3lEqa7sfqYDvjHRnqa/preview
You are calling $scope.resetMediaData(); in your submit handler which destroys the $scope.uploadMedia object including your submit function (and it doesn't get redeclared). I just moved $scope.uploadMedia = {}; outside the resetMediaData() function.
http://plnkr.co/edit/OhRwsfnx3rX3gXZ2bilc?p=preview

Intermittent "element is not found" in protractor

In Protractor, I am trying to write a function to simulate clicking a responsive navigation menu item (i.e. menu is either a bar of dropdowns across the top or a hamburger link if mobile). The structure of the bar is defined by MEANJS with a few id="" attributes mixed in.
It seems to work exactly as I want when I run it one spec at a time, like so:
protractor app/tests/e2e/conf.js --suite mySuite
but when I run with the full test (that only has 4 tests in it), like so:
protractor app/tests/e2e/conf.js
I start to get this error intermittently (source of error is in 2 places below):
Failed: element not visible
Here's my function
commonPOs.clickNavBar = function(mainTab, linkUrl) {
var deferred = protractor.promise.defer();
var hamburger = element(by.id('nav-hamburger'));
var linkCssExpression = 'a[href*="' + linkUrl + '"]';
hamburger.isDisplayed().then(function(result) {
if ( result ) {
hamburger.click().then(function() {
var navBar = hamburger
.element(by.xpath('../..'))
.element(by.id('myapp-navbar'));
return clickItNow(mainTab, linkUrl, navBar);
});
} else {
return clickItNow(mainTab, linkUrl, element(by.id('myapp-navbar')));
}
});
return deferred.promise;
function clickItNow(mainTab, linkUrl, navBar) {
var link;
if(mainTab) {
// if mainTab was passed, need to
// click the parent first to expose the link
var parentLink;
if (mainTab == 'ACCTADMIN') {
parentLink = navBar.element(by.id('account-admin-menu'));
}
else {
parentLink = navBar.element(by.linkText(mainTab));
}
expect(parentLink.isPresent()).toBeTruthy();
parentLink.click(); // FIRST PLACE ERROR HAPPENS
link = parentLink.element(by.xpath('..')).element(by.css(linkCssExpression));
}
else {
link = navBar.element(by.css(linkCssExpression));
}
expect(link.isPresent()).toBeTruthy();
link.click(); // SECOND PLACE ERROR HAPPENS
return deferred.fulfill();
}
};
I have tried to use both of these but neither work:
browser.sleep(500);
browser.driver.wait(protractor.until.elementIsVisible(parentLink));
What NOOB async error am I making?
Self answer... but any better answer will win the green check mark!!!
EDITED - After more problems, found a nice 'waitReady()' contribution from elgalu.
There were a few obvious problems with my original code, but fixing them did not solve the problem. After working through what I could, the solution seemed to be the expect(navBar.waitReady()).toBeTruthy(); lines I added. I also had to split the nested function out. Anyway, here is the new code that seems to be working now. A better (comprehensive) answer will get the green checkmark! I'm pretty sure there's a flaw or 2 here.
commonPOs.clickNavBar = function(mainTab, linkUrl) {
var deferred = protractor.promise.defer();
var hamburger = element(by.id('nav-hamburger'));
hamburger.isDisplayed().then(function(result) {
if ( result ) {
hamburger.click().then(function() {
var navBar = hamburger
.element(by.xpath('../..'))
.element(by.id('myapp-navbar'));
return clickItNow(mainTab, linkUrl, navBar, deferred);
});
} else {
return clickItNow(mainTab, linkUrl, element(by.id('myapp-navbar')), deferred);
}
});
return deferred.promise;
};
function clickItNow(mainTab, linkUrl, navBar, deferred) {
var targetLink;
var linkCssExpression = 'a[href*="' + linkUrl + '"]';
expect(navBar.waitReady()).toBeTruthy();
if(mainTab) {
// if mainTab was passed, neet to
// click the parent first to expose the link
var parentTabLink;
if (mainTab == 'ACCTADMIN') {
parentTabLink = navBar.element(by.id('account-admin-menu'));
}
else {
parentTabLink = navBar.element(by.id('main-menu-' + mainTab));
}
// expect(parentTabLink.isDisplayed()).toBeTruthy();
expect(parentTabLink.waitReady()).toBeTruthy();
parentTabLink.click();
targetLink = parentTabLink.element(by.xpath('..')).element(by.css(linkCssExpression));
}
else {
targetLink = navBar.element(by.css(linkCssExpression));
}
expect(targetLink.isDisplayed()).toBeTruthy();
targetLink.click().then(function() {
return deferred.fulfill();
});
}

Disable drag-drop while HTML5 file browse popup is open

I am working on an Angular JS application which has HTML5 file input button and a Drag - Drop area.
I need to disable the drag drop area as long as the file browse popup is open. What is the best way to achieve this?
Here is an example I just made for you, this is an updated Google DnD Controller that I made more advanced plus added the functionality you wanted.
window.fileBrowserActive = false; //init the controller to false
function DnDFileController(selector, onDropCallback) {
var el_ = document.querySelector(selector);//select our element
var overCount = 0;//over count is 0
this.dragenter = function(e)
{
e.stopPropagation();//stop propagation and prevent the default action if any
e.preventDefault();
overCount++;//increment and assign the overCount var to 1
if(fileBrowserActive == false)//if the fileBrowserAction is false we can add dropping class
{
el_.classList.add('dropping');
}
else //else add error or none at all it's your choice
{
el_.classList.add('error');
}
};
this.dragover = function(e)
{
e.stopPropagation();
e.preventDefault();
};
this.dragleave = function(e)
{
e.stopPropagation();
e.preventDefault();
if (--overCount <= 0) { //we decrement and assign overCount once if it's equal to or less than 0 remove the classes and assign overCount to 0
el_.classList.remove('dropping');
el_.classList.remove('error');
overCount = 0;
}
};
this.drop = function(e) {
e.stopPropagation();
e.preventDefault();
el_.classList.remove('dropping');
el_.classList.remove('error');
if(fileBrowserActive === false)
{ //if fileBrowserActive is false send the datatranser data to the callback
onDropCallback(e.dataTransfer);
}
else
{ //else send false
onDropCallback(false);
}
};
el_.addEventListener('dragenter', this.dragenter, false);
el_.addEventListener('dragover', this.dragover, false);
el_.addEventListener('dragleave', this.dragleave, false);
el_.addEventListener('drop', this.drop, false);
}
var isFileBrowserActive = function(e){
fileBrowserActive = true; //once clicked on it is active
this.onchange = function(e){ //create the onchange listener
if(e.target.value !== "") //if the value is not blank we keep it active
{ //so now user can't DnD AND use the file browser
fileBrowserActive = true;
}
else if(e.target.value == "") //if it is blank means they click cancel most likely
{
fileBrowserActive = false;//assign false back
} //remove the listener
this.removeEventListener('change',this.onchange,false);
};
//assign the listener for change
this.addEventListener('change',this.onchange,false);
};
var fB = document.getElementById('fileBrowser'); //grab our element for file input
fB.addEventListener('click',isFileBrowserActive,false); //assign the click event
var activation = new DnDFileController('#dragNDrop',function(e){ //grab our DnD element
console.log(e); //console log the e (either datatransfer || false)
});
Check out the This Fiddle to see how this works

AngularJS: Assign variables to $scope after AJAX call

I am sooo close I can smell the finish line --
When my app starts, I harvest the login information from the user (it's an AngularJS SPA so I can get it easy from spInfoContext) and I check to see if the user is a returning user by searching a list called itiUsers for the userId. If no records are found, I immediately create a new record in itiUsers and then present a form for the new user to enter the information that I can't grab from SharePoint. The record is created properly. When the promise returns, I am trying to populate the $scope.current_user object so that it would be the same as if this were a returning user -- that's so I only have to have one My Preferences form.
However when I log out $scope after the record is created, current_user is empty.
Here's my Controller function (i reduced values for brevity and I tried to bold the problem line):
$.when(SharePointJSOMService.getCurrentUser())
.done(function(jsonObject){
if(jsonObject.d.results.length < 1 || jsonObject.d.results.newUser ){
// new user
$.when(SharePointJSOMService.getLoggedInUser())
.done(function(jsonObject){
$scope.loggedInUser = jsonObject.d;
$scope.isNewUser = true;
$.when(SharePointJSOMService.createNewUser($scope))
.done(function(jsonObject){
**$scope.current_user.DisplayName = $scope.loggedInUser.Title;
console.log($scope);**
})
.fail(function(err){
$scope.prefPane = true;
console.info(JSON.stringify(err));
});
})
.fail(function(err){
$scope.prefPane = true;
console.info(JSON.stringify(err));
});
$scope.prefPane = true; // force preference pane
$scope.taskClose = true;
$scope.$apply();
} else {
// existing user
$scope.isNewUser = false;
$scope.prefPane = false; // hide preference pane
$scope.current_user = jsonObject.d.results[0];
switch($scope.current_user.Role){
case 'USR':
$scope.projectClose = 'true';
break;
case 'PMG':
$scope.projectClose = 'false';
break;
default:
$scope.projectClose = 'true';
break;
} // end switch
$scope.$apply();
} // end if
})
.fail(function(err){
$scope.prefPane = true;
console.info(JSON.stringify(err));
});
It crashes because you are trying to set $scope.current_user.DisplayName after creating a new user but $scope.current_user object is undefined. Try instead:
$scope.current_user = {
DisplayName: $scope.loggedInUser.Title
}

Resources