AngularJS component binding a function - angularjs

Let's say, we were trying to delete an item from the list using the web api.We had created a child component named as remove-item using parameters - item and onRemove.On click of a item,we would like to trigger the callback function to the parent component.As per the code,onRemove is not getting called after deleting the item.Can someone help us figure out the error and provide us the right solution with an illustration.
remove.component.js
-------------------
this.RemoveItem = function (index) {
var promise = productList.removeItem(parseInt(this.id));
promise.then(function (response) {
console.log("An item has been deleted");
this.items=response.data;
}, function (error) {
console.log("An error has occurred while deleting the item:", this.id);
});
this.onRemove({
$index: this.items
});
}

I would avoid using 'this'. Not sure why you passed index param in RemoveItem fn , can't see you use it anywhere in this scope. Anyway if productList.removeItem returns Promise than we can call onRemove. I would def need more information - html code and your remove fn code but try this anyway.
let vm = this;
vm.RemoveItems = RemoveItem;
vm.onRemove = onRemove;
RemoveItem(index) {
productList.removeItem(parseInt(this.id))
.then(function (response) {
console.log("An item has been deleted");
vm.onRemove({$index: response.data});
}, function (error) {
console.log("An error has occurred while deleting the item:", this.id);
});
}
onRemove(obj) {
console.log(obj);
//make your remove here
}

Related

Refresh page after APIQuickAction submission

I'm new in Lightning component development, and I'm trying to implement a lightning:datatable with several actions, like add a new line, delete a line, and create new line.
To create a line, I'm using a quick action, and I call it using quickActionAPI :
var actionAPI = component.find("quickActionAPI");
var args = { actionName :"Contrat_cadre__c.My_rule"};
var anAction = actionAPI.selectAction(args)
.then(function(result) {
})
.catch(function(e) {
if (e.errors) {
alert('The action is unavailable');
}
});
It's working as expected but well I need to manually refresh the page to see the new line in my datatable. But I don't know how to catch the subsmission of the quick action.
Try putting this in your "then" block: https://developer.salesforce.com/docs/component-library/bundle/force:refreshView/documentation
Thank you for your anwser, here is what I tried :
in controller.js :
var anAction = actionAPI.selectAction(args)
.then(function() {
console.log('enter in then');
helper.refreshPage();
})
in helper.js :
refreshPage: function (component)
{
console.log('helper method');
var action = component.get('c.**myApexController**');
action.setCallback(component,
function(response) {
var state = response.getState();
console.log(state);
if (state === 'SUCCESS'){
console.log('success');
$A.get('e.force:refreshView').fire();
} else {
//do something
}
}
);
$A.enqueueAction(action);
}
It seems that the then is fired when the action is invoked, so before the action submission. (the console.log display "enter in then" and "helper method" at this time, the other log does not display at all)

Why the execution of my code gets stuck as it encounters the function call?

I have created a function named calculateFaceLocation(). And I am trying to call calculateFaceLocation() from another function named onButtonClick(). But the execution gets stopped as soon as the function call line is encountered. I have proved this by using console.log()
calculateFaceLocation = (response) =>{
console.log('I HAVE BEAEN CALLED');
}
onButtonClick =(event) =>{
this.setState({
ImageUrl:this.state.input
})
app.models.predict(Clarifai.FACE_DETECT_MODEL, this.state.input).then(
function(response) {
// do something with response
console.log(response.outputs[0].data.regions[0].region_info.bounding_box)
this.calculateFaceLocation();
console.log('returning after call')
},
function(err) {
// there was an error
}
);
}
Usually, JavaScript functions will not have the context (this) in which they were called. You can either bind the context to the functions using bind(), or, the easier way: use arrow functions instead of normal anonymous functions, just like you did when creating onButtonClick.
Arrow functions preserve the context they were called in, so the this inside the function will the same as whatever it was in that block.
You'd end up with something like
onButtonClick =(event) =>{
this.setState({
ImageUrl:this.state.input
})
app.models.predict(Clarifai.FACE_DETECT_MODEL, this.state.input).then(
(response) => {
// do something with response
console.log(response.outputs[0].data.regions[0].region_info.bounding_box)
this.calculateFaceLocation();
console.log('returning after call')
},
(err) => {
// there was an error
}
);
}
Reason:
Context. Using this in a function will refer only to the function from where it is called.
Explanation:
In your code, the function calculateFaceLocation is declared in the parent context and hence it is not accessible from the child function's this.
Solution:
You can bind the value of this in the child funciton using bind.
You can use arrow functions which does this for you.
Bind Variable Examples:
var module = {
sayHello: function() {
return "Hello";
},
sayHelloName: function(name) {
return this.sayHello() + " " + name;
}
};
console.log(module.sayHelloName('Ram')); // Prints Hello Ram
// Now, Lets pass it to another function like in your code.
// This funciton is bound with the context of module.
// So accessing sayHello will work.
boundSayHelloName = module.sayHelloName.bind(module);
// This function doesn't have access to the sayHello function.
// It will throw Error.
unboundSayHelloName = module.sayHelloName;
console.log(boundSayHelloName('Ram')); // Prints Hello Ram
console.log(unboundSayHelloName()); // Throws Error
Code - Using arrow function:
calculateFaceLocation = (response) => {
console.log('I HAVE BEAEN CALLED');
}
onButtonClick = (event) => {
this.setState({
ImageUrl:this.state.input
})
app.models.predict(Clarifai.FACE_DETECT_MODEL, this.state.input).then(
(response) => {
// do something with response
console.log(response.outputs[0].data.regions[0].region_info.bounding_box)
this.calculateFaceLocation();
console.log('returning after call')
},
(err) => {
// there was an error
}
);
}

AngualrJS $watchCollection triggers even when arrays are equal

I am trying to implement an auto sync between my angularJS model and my database.
I am running the following function every ten seconds to get data from from database in which I update my variable products_copy:
$interval(function(){$scope.getProductsSync();},10000);
$scope.getProductsSync = function() {
var q = $q.defer();
$http({
url: '/getData/getProducts.php',
method: "POST",
data: {"user_id":$scope.user_id}
})
.then(function(response) {
if(response.data.valid)
{
console.log('Products sync complete: '+new Date().toLocaleTimeString());
console.log(response.data.products);
$scope.products_copy = response.data.products;
q.resolve('Products sync complete');
}
else if(response.data.msg=="offline")
{
console.log('Products sync offline');
q.resolve('Products sync offline');
}
else
{
console.log('Products sync error');
console.log(response);
q.reject('Products sync error');
}
},
function(response) {
console.log('Products sync error');
console.log(response);
q.reject('Products sync error');
});
return q.promise;
}
Whenever there is a change in this data I want to update my actual product list in my model which is defined by the array products. Hence, I am using the service $watchCollection to detect a change in the data and update my model when there is a change. However this change is triggered in each call even though the data from the database is unchanged.
$scope.$watchCollection('products_copy', function (newValue, oldValue, scope) {
if(newValue!==oldValue)
{
console.log('Watch on products was called');
console.log('Old value: '+oldValue);
console.log('New value: '+newValue);
$scope.products = newValue;
}
});
I want the event to be triggered only when there is change in the array such as:
add item
remove item
edit any property of any item
EDIT 1:
I changed it to angular.equals but even that resulted in trigger in every call. However, when I examined each item in the console I realised angular was adding a property $$hashkey which was varying between the items. Any idea how to solve this?
It is how it should be, because on each response you assign a new reference to $scope.products_copy and no matter that there're no changes of the data inside it, when you do newValue!==oldValue you compare the refereces, they are always different
if you try
var a = [];
var b = [];
console.log(a===b); // false
// the both are empty and seems to be equal
you have to check the data inside old and new data. Try with angular.equals
You can try for angular.equal(object1, object2)
$scope.$watchCollection('products_copy', function (newValue, oldValue, scope) {
if(!angular.equals(newValue, oldValue))
{
console.log('Watch on products was called');
console.log('Old value: '+oldValue);
console.log('New value: '+newValue);
$scope.products = newValue;
}
});
The problem was that angular was inserting a $$hashKey attribute which resulted in a difference even in same objects. Removing this field did the trick for me.

using for loop and asynchronus services in angular js

I want to iterate over a loop and call a service (which is asynchronus) for each item -
for(var i=0;i<$scope.objs.length;i++) {
var obj= $scope.objs[i];
api.invoke({
//parameters
}).then(function (members) {
$scope.setInfo(obj.name,members);
}, function (fail) {
console.log("failed");
});
}
But, as it is asynchronus , obj value is getting ovrewritten before I can send it to the method - setInfo(). How can I avoid it?
You could achieve this by using angular.forEach which would have value that will be available for that particular function level.
Code
angular.forEach($scope.objs, function(value, index) {
api.invoke({
//parameters
}).then(function(members) {
$scope.setInfo(value.name, members);
}, function(fail) {
console.log("failed");
});
})
OR same thing can be done by creating anonymous function.

How to scope methods in AnjularJS

I have this controller that has several functions that call each other. On success, I want to return something to be displayed (located in the last function). For some reason, without errors, the return is not working but the console.log is. Can someone please tell me why the return does not work and give me a solution please. Thanks so much!
.controller("dayController", function(){
.controller("weatherController", function(){
this.currentWeatherToDisplay = function(){
if(navigator.geolocation){
navigator.geolocation.getCurrentPosition(gotLocation,initialize);
}
else{
alert("Device does not support geolocation");
initialize();
}
};
var currentLocation;
//get the location coords
function gotLocation(pos){
var crd = pos.coords;
currentLocation = loadWeather(crd.latitude+','+crd.longitude);
initialize();
}
function initialize(){
if(!currentLocation){
loadWeather("Washington, DC");
}
else{
loadWeather(currentLocation);
}
}
function loadWeather(location){
$.simpleWeather({
location: location,
woeid: '',
unit: 'f',
success: function(weather) {
var html = weather.temp+'°'+weather.units.temp;
console.log(html);
return html;
},
error: function(error) {
console.log(error);
return error;
}
});
}
});
Well, mmmm you are use some jQuery plugin to get the weather given a current location, and like almost every jQuery plugins this use callbacks call to works (success, and error) first one i recommend you to rewrite this method to something like this:
function loadWeather(location){
var defered = $q.defer();
$.simpleWeather({
location: location,
woeid: '',
unit: 'f',
success: function(weather) {
var html = weather.temp+'°'+weather.units.temp;
console.log(html);
defered.resolve(html);
},
error: function(error) {
console.log(error);
defered.reject(error);
}
});
return defered.promise;
}
Also you must inject the $q dependency to the controller, like this:
module.controller("weatherController", function($q){...}
or this
module.controller("weatherController", ['$q',function($q){...}
I recommend the last by minyfication improvement in angular, when you return a promise like the function loadWeather, you must understand some basic principles about the the $q (based kriskoval Q library), a promise is a expected value in the future, an have a method then to work with that data (its a very short concept), that means:
function gotLocation(pos){
var crd = pos.coords;
loadWeather(crd.latitude+','+crd.longitude)
.then(function(html){
//html contain the expected html from loadWeather defered.resolve(html)
currentLocation = html;
})
.catch(function(error){
//error contain the expected error by execute defered.reject(error)
// maybe gonna try to initialize here
initialize();
})
}
This must work, remember to change the initialize function to some like this:
function initialize(){
var promise;
if(!currentLocation){
promise = loadWeather("Washington, DC");
}
else{
promise = loadWeather(currentLocation);
}
promise.then(function(html){
// some logic with succesful call
}, function(error) {
// some logic with error call
})
}

Resources