Ionic 1 - Popup not working properly after state change - angularjs

I have an $ionicPopup defined inside a particular controller say Controller-1. When I move to Controller-1 from any other different Controller-X by changing the state as $state.go('xxx.xx.xx'), the $ionicPopup is not working as expected. But at the same time, if I open Controller-1 for the first time, $ionicPopup works fine. State change is causing issue. How to solve it?
The code for $ionicPopup inside Controller-1 is:
$ionicPopup.show({
title: "Delivery Not Available",
subTitle: 'Selected area is beyond our delivering area. You can place only Take Away orders.',
scope: $scope,
buttons: [{
text: 'Cancel',
onTap: function(e) {
return true;
}
},
{
text: '<b>OK</b>',
type: 'button-balanced',
onTap: function(e) {
$state.go('home.app');
}
},
]});
If I directly launch it from Controller-1 for the first time, it works as expected:
Screenshot - Normal Case
But, if I move to Controller-1 from any other state through a state change using $state.go('xxx.xx.x'), it shows broken output:
Screenshot - Failing Case

Make a function like this for your popup and Call that Function in your success callback function and make sure you have this code in the same controller in which success callback is written
$scope.showConfirm = function() {
var confirmPopup = $ionicPopup.confirm({
title: 'Title',
template: 'Are you sure?'
});
confirmPopup.then(function(res) {
if(res) {
console.log('Sure!');
} else {
console.log('Not sure!');
}
});
};
Refer this link for more details on Ionic Popup

Related

Should I test calls to my service inside BootstrapDialog prompt?

I am using BootstrapDialog to show a dialog box. If the user clicks delete it calls my service and deletes it from the database. If they click cancel it closes the dialog.
I am writing unit tests and this one is puzzling me. The call to my service is nested pretty deep and I wouldn't even know how to make the tests know which path I'm testing.
My code in the controller:
$scope.deleteInventoryEntry = function(id){
//launch dialog
BootstrapDialog.show({
title: 'CONFIRM DELETION',
message: 'Are you sure you want to delete this record?',
closable: false,
type: BootstrapDialog.TYPE_DANGER,
buttons: [{
label: 'Cancel',
action: function(dialog) {
dialog.close();
}
}, {
label: 'Delete',
icon: 'glyphicon glyphicon-remove',
cssClass: 'btn-danger',
action: function(dialog) {
//remove item from database
tankService.deleteInventoryEntry(id).success(function (response) {
//remove item from table if successful
if(response > 0){
//figure out which item to remove from table
var pos = $scope.invTable.filtered.map(function(item) { return item._id; }).indexOf(id);
//remove from table
$scope.invTable.filtered.splice(pos,1);
$scope.selectedItem.lineItems = [];
dialog.close();
//$scope.successGrowl(' QC Deleted Successfully');
}
});
}
}
]
});
};
My Test
it('prompts on delete inventory item', function(){
spyOn(BootstrapDialog, 'show').and.callThrough();
$scope.deleteInventoryEntry(1);
expect(BootstrapDialog.show).toHaveBeenCalled();
});
I can also test if say the ID was NAN or Null and the dialog shouldn't show. But I'm just curious if I should be somehow testing tankService.deleteInventoryEntry() was called. I feel like I should but does that mean I have to mock this entire dialog item?
Any help to point me in the right direction would be much appreciated.
Thanks!
Rule of thumb to any testing. Don't test the implementation, but the behavior. For instance you should test that when you filled a form and clicked a submit button it was sent to your API and something happened in response. Tests should be independent from the view part as much as possible (eg. was the form located in a modal or somewhere in the page).

Can't workout how to reload angular-datatable after deleting records from the database

I can't seem to work out how to redraw my Angular-Datatable after I delete a record from my database. I don't get any errors, but the table never seems to redraw unless I manually refresh the page. I have been trying to work with many examples from the website documentation.
I have my datatable:
$scope.dtInstance = {};
$scope.selectedItems = [];
$scope.toggleItem = toggleItem;
$scope.reloadData = reloadData;
// Build the User table
$scope.dtOptions = DTOptionsBuilder
.fromFnPromise(function() {
var deferred = $q.defer();
deferred.resolve(users);
return deferred.promise;
})
.withBootstrap() // Style with Bootstrap
.withOption('responsive', true)
.withDisplayLength(15) // Show 15 items initially
.withOption('order', [0, 'asc']) // Sort by the first column
.withOption('lengthMenu', [15, 50, 100]) // Set the length menu items
.withOption('createdRow', function(row, data, dataIndex) {
// Recompiling so we can bind Angular directive to the DT
$compile(angular.element(row).contents())($scope);
})
.withOption('headerCallback', function(header) {
if (!$scope.headerCompiled) {
// Use this headerCompiled field to only compile header once
$scope.headerCompiled = true;
$compile(angular.element(header).contents())($scope);
}
})
.withOption('fnRowCallback', formatCell);
$scope.dtColumns = [
DTColumnBuilder.newColumn(null).withTitle('Username').withClass('col-md-2').renderWith(createUsernameHyperlink),
DTColumnBuilder.newColumn('Email').withTitle('Email'),
DTColumnBuilder.newColumn('Level').withTitle('Role').withClass('col-md-2'),
DTColumnBuilder.newColumn('LastConnected').withTitle('Last Accessed'),
DTColumnBuilder.newColumn('Verified').withTitle('Account Verified').withClass('col-md-2'),
DTColumnBuilder.newColumn(null).withTitle('')
.notSortable()
.renderWith(function(data, type, full, meta) {
return '<input type="checkbox" ng-click="toggleItem(' + data.Id + ')" />';
}).withClass("text-center")
];
// Reload the datatable
function reloadData() {
var resetPaging = false;
$scope.dtInstance.reloadData(callback, resetPaging);
};
function callback(json) {
console.log(json);
};
And then I have my delete function that sits in the same controller. Calling reloadData() on a successful response from the service. I can see from the console.log that it is calling the function correctly, but nothing happens.
$scope.deleteUser = function( selectedItems ) {
swal({
title: 'Are you sure?',
text: 'Are you sure you want to delete the selected account profile(s)? This process cannot be undone...',
type: 'warning',
showCancelButton: true,
confirmButtonText: 'Delete',
confirmButtonColor: "#DD6B55",
closeOnConfirm: false,
allowEscapeKey: true,
showLoaderOnConfirm: true
}, function() {
setTimeout( function() {
// Delete user
UsersService.deleteUser( selectedItems.toString() )
.then(function( data ) {
// Show a success modal
swal({
title: 'Success',
text: 'User has been deleted!',
type: 'success',
confirmButtonText: 'Close',
allowEscapeKey: false
}, function() {
reloadData(); //<== Calls the function but doesn't do anything
//$state.go('users');
});
}, function() {
// Show an error modal
swal({
title: 'Oops',
text: 'Something went wrong!',
type: 'error',
confirmButtonText: 'Close',
allowEscapeKey: true
});
});
}, 1000);
});
};
Just wondering if I have missed some step?
As suggested by #davidkonrad in a previous comment and more so from the Angular-Datatable's author, I was not reloading my content when attempting to redraw my table. Even though I was referencing my data (users) from an injected service, it was never getting updated within the controller and so my table content was never differing.
The author suggested that it is preferable to load the data from a promise that makes a HTTP request, thus allowing further calls to the promise each time the table redraws.
So instead of this:
// Build the User table
$scope.dtOptions = DTOptionsBuilder
.fromFnPromise(function() {
var deferred = $q.defer();
deferred.resolve(users);
return deferred.promise;
})
.withBootstrap() // Style with Bootstrap
I changed it to this:
// Build the User table
$scope.dtOptions = DTOptionsBuilder
.fromFnPromise(function() {
return UsersService.getUsers();
})
.withBootstrap() // Style with Bootstrap
Which now updates my table fine upon each redraw event with a call to $scope.dtInstance.reloadData();
My Github post can be found here
setTimeout function works from outside of the angular digest cycle since it's async. If you want actions you take inside a timeout to apply to the angular digest cycle you should use $timeout instead.
Another option is to use $scope.apply(), but this will just mimic the $timeout function.
Please note that you'll need to inject $timeout to your controller.

Overwrite Ext Direct callback or something?

I have many Ext Direct call, and I need to show a Message Box after the result arrived.
Direct.Class.Function (params, function (result) {
// need to show message box in many ajax result like this
//...
})
Is there any solution to this? Can I overwrite or make a default callback before unique callback somehow?
I found it! :)
Ext.direct.Manager.on('message', function(e){
Ext.Msg.show({
title: "Message",
msg: e.text,
buttons: Ext.Msg.OK,
icon: Ext.Msg.INFO,
fn: function (btn) {
location.href = e.url;
},
scope: this
});
});

What is event.preventDefault preventing despite the event?

One goal of my main controller is to prevent users from going to urls of other users. That works perfectly fine with listening on $locationChangeStart and using its events preventDefault method. Unfortunately calling this method has the strange side effect of somehow "interrupting" the work of the function "handleNotification" which has the goal of notifying the user for 2 seconds that she or he has done something illegitimate. If I comment out event.preventDefault(), everything works as expected. So my question is: What is the 'scope' of the 'default' preventDefault prevents that I don't have on my mind and which keeps the handleNotification function from working properly?
$scope.$on('$locationChangeStart', function(event, newUrl, oldUrl) {
ifUserIs('loggedIn', function() {
if (newUrl.split('#/users/')[1] !== $scope.user.userId) {
handleNotification('alert', 'You are not allowed to go here.');
event.preventDefault();
}
});
});
function handleNotification (type, message) {
$scope.notice = {
content: message,
type: type
};
$timeout(function() {
delete $scope.notice;
return true;
}, 2000);
}
Update below
Ok. The problem is somewhere else. In the related jsfiddle everything works fine. After finding the source which is responsible for this strange behaviour I will let you know.
<html ng-app="mapApp">
<div ng-controller="mainCtrl">
<global-error message="{{notice.content}}"></global-error>
</div>
</html>
And the code.
var mapApp = {};
mapApp = angular.module('mapApp', []);
mapApp.controller('mainCtrl', function ($scope, $location, $timeout) {
$location.path('users/2')
$scope.$on('$locationChangeStart', function (event, newUrl, oldUrl) {
handleNotification('alert', 'You are not allowed to go here.');
event.preventDefault();
});
function handleNotification(type, message) {
$scope.notice = {
content: message,
type: type
};
$timeout(function () {
delete $scope.notice;
console.log('deleted');
return true;
}, 2000);
$scope.$digest();
}
});
mapApp.directive('globalError', function () {
return {
restrict: 'E',
scope: {
message: '#',
type: '#'
},
template: "<div class=\"alert-box {{type}}\">\
<p>\
{{message}}\
</p>\
</div>"
};
});
Update
Ok. One step further. And the problem is still there. Right now I know that changing the path in the browser is something different than changing the url by putting $location.path('users/2') inside the code (see above). While $location.path('users/2') works as expected, changing the path in the browsers address bar manually just makes the address jump back to the old address without displaying the notice. So event.preventDefault() works correctly but handleNotification('alert', 'You are not allowed to go here.') isn't. Strange.
Update 2
Adding $scope.$digest() to the end of the handleNotification function did the trick.

extjs, php works on double click, and i want to work on one click

in my php code i have a table with rows:
name actions
category 1 edit
category 2 edit
..... edit
every edit buttons have an id for ex: <a href="edit('.$raw['id'].')" id="show-btn'.$raw['id'].'">
now my function edit is:
var win;
var button;
function edit(idd){
button = Ext.get('show-btn'+idd);
button.on('click', function(){
// create the window on the first click and reuse on subsequent clicks
if(!win){
win = new Ext.Window({
applyTo:'hello-win',
layout:'column',
closeAction:'hide',
plain: true,
autoHeight:true,
items: new Ext.FormPanel({
applyTo: 'hello-tabs',
}),
buttons: [{
text:'Modify',
handler: function(){
win.hide();
document.form_edit.submit();
}
},{
text: 'Close',
handler: function(){
win.hide();
}
}]
});
}
win.show(this);
});
};
This script works perfectly but on bauble click, how can i do this on one click.
I now the problem is on button.on('click')
Many thanks, please help me with this issues
It seems like some level of functionality is being added on your first click and then that is used for subsequent clicks. I'd suggest putting either an alert or a console.log (if your browser supports it) inside of the edit function both before and after the if(win) test.
I'm also curious -- if you're trying to have this execute for an entire table, wouldn't that win global variable cause problems?
I think you're better off pre-populating win and using a local variable:
function edit(idd){
button = Ext.get('show-btn'+idd);
// this can be moved into button.on('click', function(){, but that may be
// causing the problem...
// come to think of it... the example here:
// http://dev.sencha.com/deploy/dev/examples/window/hello.js
// has this inside the button.on method. You may want to try it both ways.
if(!button.win){
button.win = new Ext.Window({
applyTo:'hello-win',
layout:'column',
closeAction:'hide',
plain: true,
autoHeight:true,
items: new Ext.FormPanel({
applyTo: 'hello-tabs',
}),
buttons: [{
text:'Modify',
handler: function(){
win.hide();
document.form_edit.submit();
}
},{
text: 'Close',
handler: function(){
win.hide();
}
}]
});
}
button.on('click', function(){
// the window already exists, so no need to worry about creating it.
button.win.show(this);
});
};
Could that work? If not, we will need to see more code.

Resources