Salesforce Lightning: Controller functions interaction within the same component - salesforce

Do anyone know "how to call a lightning controller function from another function within the same lightning component?"
Thanks
Aruna
({
doInit: function(component, event, helper){
var action = component.get("c.gettemps");
action.setParams({ recordId : component.get("v.recordId") });
action.setCallback(this, function(response){
var parsedJSON= JSON.parse(response.getReturnValue());
var size=component.get("v.limit");
var counter = component.get("v.counter");
component.set("{!v.myObject}",parsedJSON);
var list=[];
for(var i=0; i<size;i++)
{
list.push(parsedJSON[i]);
counter++;
}
component.set("v.end",counter);
component.set("{!v.counter}",counter);
component.set("{!v.paginationList}",list);
});
$A.enqueueAction(action);
},
next:function(component,event,helper)
{
var myObject = component.get("v.myObject");
var size=component.get("v.limit");
var end = component.get("v.end");
var counter = component.get("v.counter");
var list=[];
for(var i=end; i<end+size; i++)
{
if(i<myObject.length)
{
if(i>-1)
{
list.push(myObject[i]);
counter++;
}
}
}
component.set("v.end",counter);
component.set("{!v.counter}",counter);
component.set("{!v.paginationList}",list);
},
previous:function(component,event,helper)
{
var myObject = component.get("v.myObject");
var size=component.get("v.limit");
var end = component.get("v.end");
var counter = component.get("v.counter");
var list=[];
for(var i=end-1; i>end-size-1; i--)
{
if(i>=-1)
{
list.push(myObject[i-1]);
counter--;
}
}
component.set("v.end",counter);
component.set("{!v.counter}",counter);
component.set("{!v.paginationList}",list);
}
})
Actually I have problem with my previous function. When I stay in my first page and selects previous button my page should not be changed but my code is behaving abnormally. So I thought of reusing my doInit function to stay in the current page when I am already in the first page. Please help
Thanks
Aruna

In the helper it is possible by "this" operator
this.next();
In the controller you cannot do this directly.
But i have one solution for you :)
Create method handler in component .
Then you can call this method in controller and helper by componet.methodName function
component.triggerNextFun();

You can also try this way
JS Controller :
({
doInit : function(component, event, helper){
var action = component.get("c.getBeforeAWBDetails");
action.setParams({
"CaseId" : component.get("v.recordId")
});
console.log("caseId :" + component.get("v.recordId"));
action.setCallback(this, function(response) {
var state = response.getState();
if(component.isValid() && state == "SUCCESS"){
component.set("v.BeforeAWB", response.getReturnValue());
}
});
$A.enqueueAction(action);
},
closeModal : function(component, event, helper) {
$A.get('e.force:refreshView').fire();
var reInit = component.get("c.doInit");
// use this and extend the values you need to get from "doInit" method
$A.enqueueAction(reInit);
}
})

Related

Delay loading data in Angular JS

I have code like this
(function (app) {
app.controller('productListController', productListController)
productListController.$inject = ['$scope', 'apiService', 'notificationService', '$ngBootbox', '$filter'];
function productListController($scope, apiService, notificationService, $ngBootbox, $filter) {
$scope.products = [];
$scope.page = 0;
$scope.pagesCount = 0;
$scope.getProducts = getProducts;
$scope.keyword = '';
$scope.search = search;
$scope.deleteProduct = deleteProduct;
$scope.selectAll = selectAll;
$scope.deleteMultiple = deleteMultiple;
function deleteMultiple() {
var listId = [];
$.each($scope.selected, function (i, item) {
listId.push(item.ID);
});
var config = {
params: {
checkedProducts: JSON.stringify(listId)
}
}
apiService.del('/api/product/deletemulti', config, function (result) {
notificationService.displaySuccess('Deleted successfully ' + result.data + 'record(s).');
search();
}, function (error) {
notificationService.displayError('Can not delete product.');
});
}
$scope.isAll = false;
function selectAll() {
if ($scope.isAll === false) {
angular.forEach($scope.products, function (item) {
item.checked = true;
});
$scope.isAll = true;
} else {
angular.forEach($scope.products, function (item) {
item.checked = false;
});
$scope.isAll = false;
}
}
$scope.$watch("products", function (n, o) {
var checked = $filter("filter")(n, { checked: true });
if (checked.length) {
$scope.selected = checked;
$('#btnDelete').removeAttr('disabled');
} else {
$('#btnDelete').attr('disabled', 'disabled');
}
}, true);
function deleteProduct(id) {
$ngBootbox.confirm('Are you sure to detele?').then(function () {
var config = {
params: {
id: id
}
}
apiService.del('/api/product/delete', config, function () {
notificationService.displaySuccess('The product hase been deleted successfully!');
search();
}, function () {
notificationService.displayError('Can not delete product');
})
});
}
function search() {
getProducts();
}
function getProducts(page) {
page = page || 0;
var config = {
params: {
keyword: $scope.keyword,
page: page,
pageSize: 20
}
}
apiService.get('/api/product/getall', config, function (result) {
if (result.data.TotalCount == 0) {
notificationService.displayWarning('Can not find any record.');
}
$scope.products = result.data.Items;
$scope.page = result.data.Page;
$scope.pagesCount = result.data.TotalPages;
$scope.totalCount = result.data.TotalCount;
}, function () {
console.log('Load product failed.');
});
}
$scope.getProducts();
}
})(angular.module('THTCMS.products'));
So my problem is when i loading data the application take me some time to load data.
I need load data as soon as
Is the any solution for this?
Since you are loading data via api call, there will be a delay. To handle this delay, you should display a loading screen. Once the data is loaded, the loading screen gets hidden and your main screen is visible. You can achieve this using $http interceptors.
See : Showing Spinner GIF during $http request in angular
The api-call is almost certainly causing the delay. Data may be received slowly via the api-call so you could display any sort of loading text/image to notify the use that the data is being loaded.
If u want the data ready at the time when controller inits, u can add a resolve param and pass the api call as a $promise in the route configuration for this route.

AngularJS update Service values when connected or disconnected to firebase

I wish to change the icon color when connected or disconnected to the firebase server. I got this far:
HTML
<button class="button button-icon ion-cloud" ng-style="dbConnectedStyle"></button>
Controller
firebaseRef.$loaded().then( function() {
$scope.dbConnectedStyle = {'color': dbConnectStatus.color};
}
Service
.service('dbConnectStatus', function(firebaseRef){
var status = false;
var color = 'transparent';
var connectedRef = firebaseRef.child(".info/connected");
connectedRef.on("value", function(snap) {
status = snap.val();
if (status) {
color = 'lightgrey';
console.log("Connected to DB (" + color + ")" );
} else {
color = 'transparent';
console.log("Disonnected to DB (" + color + ")" );
}
});
return {
'boolean': status,
'color': color
}
})
It change color the first time. But when disconnecting it doesn't change... seems like it's not two-way binding to the service. How do I achieve this?
UPDATE
Tried to do a reference to the Service as an object rather than doing primitives assignments as explained in the good tutorial A Tale of Frankenstein and Binding to Service Values in Angular.js
I changed the code to the following
HTML
<button class="button button-icon ion-cloud"
ng-style="dbConnectionStatus.connectionStyle">
</button>
Service
.service('dbConnectStatus', function(firebaseRef, $rootScope){
this.status = false;
var styles = {
'offlineStyle': {'color': 'red'},
'onlineStyle': {'color': 'lightgrey'}
};
this.connectionStyle = styles.offlineStyle;
firebaseRef.child(".info/connected")
.on("value",
function(snap) {
this.status = snap.val();
if (snap.val()) {
console.log("Connected to DB.");
this.connectionStyle = styles.onlineStyle;
console.log(this.connectionStyle);
} else {
console.log("Disconnected to DB.");
this.connectionStyle = styles.offlineStyle;
console.log(this.connectionStyle);
}
console.log(this.status);
$rootScope.$broadcast('dbConnection:changed');
}
);
})
Controller
$scope.dbConnectionStatus = dbConnectStatus;
$scope.$on('dbConnection:changed', function() {
console.log("'on(...)' called. This is the $scope.dbConnectionStatus.connectionStyle:");
$scope.dbConnectionStatus = dbConnectStatus;
console.log($scope.dbConnectionStatus.connectionStyle);
console.log("This is the dbConnectStatus.connectionStyle:");
console.log(dbConnectStatus.connectionStyle);
});
$rootScope.$watch('dbConnectStatus', function (){
$scope.dbConnectionStatus = dbConnectStatus;
});
//$rootScope.$apply();
I then reloaded the code and got this console message
I then turned off the connection
I then turn on the connection
It is clear to me that the service dbConnectionStatus isn't updated as a global variable in the way that I expected. I was on the assumption that a service is called once when the application is load and that assigning a scope variable to a service (object) is not a call but a reference...
What am I doing wrong?
I worked in a jsFiddle using $emit and $on to handle the status changes inside the service. The main problem is that when going online the angular binding was not working properly so I needed to force an angular cycle with $scope.$apply().
I started working on the first version of your code but made some refactoring. You can find the full code on the jsFiddle but the service and the controller look like the following:
Service
.service('dbConnectStatus', function($rootScope){
var status = false;
var color = 'red';
var self = {
startWatchingConnectionStatus: function(){
var connectedRef = firebase.database().ref().child(".info/connected");
connectedRef.on("value", function(snap) {
console.log(snap.val());
status = snap.val();
if (status) {
color = 'blue';
console.log("Connected to DB (" + color + ")" );
} else {
color = 'red';
console.log("Disonnected to DB (" + color + ")" );
}
$rootScope.$emit('connectionStatus:change', {style: {'color': color}, status: status}});
});
},
getStatus: function(){
return status;
},
getColor: function(){
return color;
}
};
return self;
})
Controller
.controller('HomeCtrl', ['$scope', 'dbConnectStatus', '$rootScope',function($scope, dbConnectStatus, $rootScope) {
dbConnectStatus.startWatchingConnectionStatus();
$rootScope.$on('connectionStatus:change', function currentCityChanged(event, value){
$scope.color = value.style;
//if changed to connected then force the $apply
if(value.status === true){
$scope.$apply();
}
});
}]);
Let me know if there is anything that is still not clear.
Inspired from #adolfosrs great answer I found the following solution to work for me.
Service
.service('dbConnectStatus', function(firebaseRef, $rootScope){
// Initial setup
var styles = {
'offlineStyle': {'color': 'red'},
'onlineStyle': {'color': 'skyeblue'}
};
// Functions to switch status
var offline = function () {
this.boolean = false;
this.style = styles.offlineStyle;
}
var online = function () {
this.boolean = true;
this.style = styles.onlineStyle;
}
var get_status = function(){
return {
boolean: this.boolean,
style: this.style
}
}
// Read the firebase info and update when changed
firebaseRef.child(".info/connected")
.on("value", function(snap) {
if (snap.val()) {
online();
} else {
offline();
}
$rootScope.$emit('dbConnection:changed', get_status() );
});
})
Controller
// Hide it before the status is known.
$scope.dbConnectionStatus = {'color': 'transparent'};
// Getting and reading status changes
$rootScope.$on('dbConnection:changed', function(event, status) {
$scope.dbConnectionStatus = status.style;
$scope.$apply();
});
You should be able to get this working simply by storing the color in an object in the service and referencing it from the controller. e.g.
View
<button class="button button-icon ion-cloud" ng-style="dbStatusService.style"></button>
Controller
$scope.dbStatusService = dbConnectStatus;
Service
.service('dbConnectStatus', function(firebaseRef){
var status = false;
var style = {color: 'transparent'};
var connectedRef = firebaseRef.child(".info/connected");
connectedRef.on("value", function(snap) {
status = snap.val();
if (status) {
style.color = 'lightgrey';
} else {
style.color = 'transparent';
}
});
return {
'boolean': status,
'style': style
}
});

Issue With MD-Dialog

I am having an MD-dialog controller like below.
var HomeController = function ($scope) {
$scope.demoNonLinear = function () {
var element = document.querySelector('.mdl-stepper#stepper-non-linear');
if (!element) return false;
var stepper = element.MaterialStepper;
var steps = element.querySelectorAll('.mdl-step');
var step;
// Upgrade the component.
if (typeof componentHandler === 'undefined') {
console.log('Missing componentHandler');
} else {
console.log('componentHandler is available');
componentHandler.upgradeAllRegistered();
}
for (var i = 0; i < steps.length; i++) {
step = steps[i];
step.addEventListener('onstepnext', function (e) {
setTimeout(function () {
stepper.next();
}, 4000);
});
}
};
};
The line
var element = document.querySelector('.mdl-stepper#stepper-non-linear');
is not working on the md-dialog html instead it works on the main document. Ho can I make it work on my md-dialog content ?
Plunker link
"https://plnkr.co/edit/ixMI8FKbhyTgL5sYieVa?p=preview"
Try this to select your element in angular.
var element = angular.element( document.querySelector( '#stepper-non-linear' ) );
EDIT FOR GOOD APPROACH
I've wrapped the function in a angular.element(document).ready event which will be executed when document is ready rather than the $timeout approach.
DEMO PLUNKER

Backbone view not removing properly?

There is something I'm missing here it seems my view is not removing.
// ROUTER //
screensaveroff: function() {
AnimationManager.outAnimation([self.screensaverView], function() {
console.log($(this.screensaverView.el).length); //!! always trigger 1 !!
});
}
// ANIMATION MANAGER outANimation function (trigger outAnimation for the passed view as arg)//
outAnimation : function(animationArray, callback){
var time = [];
window.animationArray = animationArray;
for (var i=0; i<animationArray.length; i++)
{
var view = animationArray[i];
view.outAnimation();
time[i] = animationArray[i].animationTime;
}
var timeoutMax = Math.max.apply(null, time);
setTimeout(function(){callback()},timeoutMax);
}
// screensaverView outANimation function //
outAnimation: function() {
var self = this;
this.$el.slideToX(1920, self.animationTime, function() {
self.clearIntervalAnimation();
self.remove();
});
},
any idea what's wrong with my code ?? thanks a lot

Angular js not updating dom when expected

I have a fiddle for this, but basically what it's doing it geo-encoding an address that is input into a textbox. After the address is entered and 'enter' is pressed, the dom does not immediately update, but waits for another change to the textbox. How do I get it to update the table right after a submit?
I'm very new to Angular, but I'm learning. I find it interesting, but I have to learn to think differently.
Here is the fiddle and my controller.js
http://jsfiddle.net/fPBAD/
var myApp = angular.module('geo-encode', []);
function FirstAppCtrl($scope, $http) {
$scope.locations = [];
$scope.text = '';
$scope.nextId = 0;
var geo = new google.maps.Geocoder();
$scope.add = function() {
if (this.text) {
geo.geocode(
{ address : this.text,
region: 'no'
}, function(results, status){
var address = results[0].formatted_address;
var latitude = results[0].geometry.location.hb;
var longitude = results[0].geometry.location.ib;
$scope.locations.push({"name":address, id: $scope.nextId++,"coords":{"lat":latitude,"long":longitude}});
});
this.text = '';
}
}
$scope.remove = function(index) {
$scope.locations = $scope.locations.filter(function(location){
return location.id != index;
})
}
}
Your problem is that the geocode function is asynchronous and therefore updates outside of the AngularJS digest cycle. You can fix this by wrapping your callback function in a call to $scope.$apply, which lets AngularJS know to run a digest because stuff has changed:
geo.geocode(
{ address : this.text,
region: 'no'
}, function(results, status) {
$scope.$apply( function () {
var address = results[0].formatted_address;
var latitude = results[0].geometry.location.hb;
var longitude = results[0].geometry.location.ib;
$scope.locations.push({
"name":address, id: $scope.nextId++,
"coords":{"lat":latitude,"long":longitude}
});
});
});

Resources