Why is not updated scope in Angular JS? - angularjs

I have the following code Angular JS:
appService.get({id : id}).then(function (response) {
$scope.vm.events.push({title: 'New event', type: 'important', draggable: true, resizable: true});
})
This code returns response from AJAX service and puts object to array $scope.vm.events.
So, in template I dont see this added element as: {{vm.events}}
There is also one function in the same controller:
$scope.add = function (){
$scope.vm.events.push({title: 'New event', type: 'important', draggable: true, resizable: true});
}
When I call it I see new element in template: {{vm.events}}.
Why does not work code in the first case?

This is because the callback function in your service is outside the angularjs digest cycle.
For tackling this, there are two ways:
Method 1:
The first way would be to use $scope.$apply just after your callback in the service has finished as follows:
appService.get({id : id}).then(function (response) {
$scope.vm.events.push({title: 'New event', type: 'important', draggable: true, resizable: true});
$scope.$apply(); //this for updating your scope outside the digest cycle
})
Method 2:
Wrapping your service code inside a function inside the controller's scope as follows:
$scope.fn = function() {
appService.get({id : id}).then(function (response) {
$scope.vm.events.push({title: 'New event', type: 'important', draggable: true, resizable: true});
})
}
So, in this method, whenever you want to call the service just call this function. This is also the reason why your 'add' function updates the template because it is in the 'scope' of the controller and in the digest cycle.

If you are not seeing it, it is because the promise is not being resolved.
Do try putting something in the rejection handling part of the promise (on a second function within the 'then()' block):
appService.get({id : id}).then(function (response) {
$scope.vm.events.push({title: 'New event', type: 'important', draggable: true, resizable: true});
},
function(){
$scope.vm.events.push({title: 'ERROR_EVENT', type: 'ERROR_CALLBACK', draggable: true, resizable: true});
});
Like others suggested, if this is outside of angular, please call for $scope.$apply() or $scope.$digest() to trigger a digest cycle so that your data can be updated.
By adding this second function you should be able to see if the promise was being resolved or not, and if the problem lies elsewhere.

Related

Ionic 1 - Popup not working properly after state change

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

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.

Return a formatted array of events

I'm trying to integrate Angular Bootstrap Calendar to my Laravel 5 project. Right now, the calendar works using the provided pre-populated demo list of events.
vm.events = [
{
title: 'An event',
type: 'warning',
startsAt: moment().startOf('week').subtract(2, 'days').add(8, 'hours').toDate(),
endsAt: moment().startOf('week').add(1, 'week').add(9, 'hours').toDate(),
draggable: true,
resizable: true
}, {
title: 'Event 2',
type: 'info',
startsAt: moment().subtract(1, 'day').toDate(),
endsAt: moment().add(5, 'days').toDate(),
draggable: true,
resizable: true
}, {
title: 'This is a really long event title that occurs on every year',
type: 'important',
startsAt: moment().startOf('day').add(7, 'hours').toDate(),
endsAt: moment().startOf('day').add(19, 'hours').toDate(),
recursOn: 'year',
draggable: true,
resizable: true
}
];
I would like to retrieve and format the events from my database like the example above, but I'm not sure how to tackle this from my controller.
On the Angular Calendar side, I've read that I can use the angular $http service to load the events, like this:
$http.get('/events').success(function(events) {
//TODO - format your array of events to match the format described in the docs
$scope.events = events; //Once formatted correctly add them to the scope variable and the calendar will update
});
Any help would be greatly appreciated
What you would want to do is create a service that takes care of all the HTTP request/response handling and have your controller consume it to get/save/update data. Something like:
// assuming that you have a REST service endpoint at /events
// create your service that will handle all HTTP interaction for the events resource
app.factory('EventsService', ['$http', function($http) {
return {
getAll: function() {
// fetch all events asynchronously
return $http.get('/events').success(function(response) {
var events = response.data;
// if you need to do any pre-processing of the events first, do it here
// pass your events to the next function in the promise chain.
return events;
}, function(err) {
// handle errors here
// pass your error object down the chain in case other error callbacks are added later on to the promise.
return err;
});
}
};
}]);
app.controller('YourController', ['$scope', 'EventsService', function($scope, EventsService) {
// call the asynchronous service method and add your promise success callback that returns your array of events to be bound to your context.
EventsService.getAll().then(function(evts) {
$scope.events = evts;
}, function(err) {
// do any additional error handling here
});
});

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

Backbone.js - Collection keeps getting reset after fetch.success gets called

I have existing items in a collection and I want to call fetch with a different url to bring in other items that will be merged in.
For some reason reset is being called even if I use the reset:false flag and I think it has something to do with my success callback.
Is there anyway to disable the reset event and still use the success callback?
My fetch looks like this:
self.collection.fetch({
url: url,
add: true,
reset: false,
success: function() {
self.render();
$('.loading').hide();
},
error: function() {
$('.loading').hide();
}
});
I have already faced this problem and solved like this. You can also try this
self.collection.fetch({
url: url,
add: true,
add: true,
remove: false,
update: true,
success: function() {
self.render();
$('.loading').hide();
},
error: function() {
$('.loading').hide();
}
});

Resources