How can I refresh datatable in Wire using refreshApex - datatables

#wire(_getContacts,{recordId:'$recordId'}) wiredContacts({error,data}){
this.dataToRefresh = data;
if (data) {
this.contacts = this.dataToRefresh.recordList;
this.ContactsRecords = this.dataToRefresh.cList;
this.contactsSize = " Case Contacts (" + this.contacts.length + ")";
}else{
//
}
};
relateContacts() {
this.showSpinner = true;
this.showtable=false;
relateContacts({contacts: this.selected, recordId: this.recordId})
.then(data => {
this.showSpinner=false;
this.showtable=true;
this.showSuccessMessage();
refreshApex(this.dataToRefresh);
//location.reload();
this.isShowModal = false;
})
.catch(error => {
console.log(error);
this.showSpinner=false;
const evt = new ShowToastEvent({
title: 'Application Error',
message: error.body.message,
variant: 'error',
mode: 'sticky'
});
this.dispatchEvent(evt);
this.showSpinner = false;
});
}
For this code, I tried refreshApex with all possible ways. but I'm not sure the miss here. I've Checked all the blogs but everywhere, the solution is mentioned.
Tried refreshApex like below :
#wire(_getContacts,{recordId:'$recordId'}) wiredContacts({data}){
this.dataToRefresh = data;
But this also does not work

Ah that is a fun one ! Your issue is using destructuring in wiredContacts as the parameter.
(The {data} or {data,error} normally works as a parameter to the function being called back, except if you have to do refresh) Try this instead.
#wire(_getContacts,{recordId:'$recordId'}) wiredContacts(value){
this.dataToRefresh = value;
const {data, error} = value;
//Rest of you code now with data and error
}
Then in your other method you can do:
method(){
refreshApex(this.dataToRefresh);
}
Salesforce does show doing this in their example code, but it’s easy to miss and experience the fun you have been having with this.
https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.apex_result_caching
See the last example on their page.

Related

TypeError: response.data is undefined

I'm having problems with promise response for a vForm PUT to UPDATE a model (backend in laravel).
The response code is 200 (OK, updated) and the model is updated, but I don't know why I'm having error with "response.data" in catch. There is no error and code in ".then()" is running correctly.
EDIT
Service Update funciton (vue) using vForm.
updateService(){
this.$Progress.start();
this.service.put('api/service/' + this.service.id)
.then( function (response) {
Toast.fire({
type: 'success',
title: response.data['Response']
});
this.$Progress.finish();
})
.catch( function (response) {
console.log(response);
Swal.fire("Error!", response.data['Response'], "warning");
this.$Progress.fail();
});
this.$events.$emit('ServiceInform');
},
Function in backend (laravel).
public function update(Request $request, Service $service)
{
$this->validate($request, [
'id_customers' => 'required|int',
'date' => 'required|date',
'id_technicians' => 'required|int',
'location' => 'required|string',
'details' => 'required|string'
]);
if ($request['id_technicians'] !== $service['id_technicians']) {
$assignated_by = Auth::user()->id;
$assigned_date = date('Y-m-d H:i:s');
} else {
$assignated_by = $service['assignated_by'];
$assigned_date = $service['assigned_date'];
}
if ($request['id_technicians'] == 0) {
$state = 'P';
} else {
$state = 'I';
}
$service->date = $request['date'];
$service->id_technicians = $request['id_technicians'];
$service->location = $request['location'];
$service->details = $request['details'];
$service->assigned_date = $assigned_date;
$service->assigned_by = $assignated_by;
$service->state = $state;
try {
$service->save();
return Response::json([
'Response' => 'Servicio actualizado.'
], 201);
} catch (Exception $e) {
return Response::json([
'Response' => 'No se actualizó el servicio.'
], 422);
}
}
This line looks problematic to me:
this.$Progress.finish();
It's trying to access this within the function passed to then. It seems unlikely that this will be referencing what you're expecting. You should be able to confirm with suitable console logging. My suspicion is that attempting to call this.$Progress.finish() will throw an error, triggering the catch.
Try using arrow functions for your then and catch callbacks instead.

How to count the number of elements in this particular object

I am making a call to an API and the response is somehow what I expect. However, I want to count the number of elements returned and I can not do it. This is what I think is important from the code.
Call in Vue component
data(){
return {
messages: {}
}
},
loadMessages(){
axios.get("api/messagesmenu")
.then((data) => { this.messages = data.data})
}
Api controller
public function index(){
$messages = Message::all()->where('read_at', NULL);
if(isset($messages)){
foreach($messages as $message){
$from = User::find($message->from_id);
$message->fromPrenom = $from->first_name;
$message->fromNom = $from->last_name;
$message->fromImage = $from->user_image;
}
}else{
$messages = [];
}
return $messages;
}
Type of response from the API
{"3":{"id":560,"from_id":2,"to_id":1,"content":"tgr","created_at":"2019-07-15 16:59:03","read_at":null,"fromPrenom":"abdel1","fromNom":"Hidalgo","fromImage":"user2-160x160.png"}}
I want to count the number of objects I obtain. if (in vue component) I do
this.messages.length
it returns undefined
Try this:
const messages = {"3":{"id":560,"from_id":2,"to_id":1,"content":"tgr","created_at":"2019-07-15 16:59:03","read_at":null,"fromPrenom":"abdel1","fromNom":"Hidalgo","fromImage":"user2-160x160.png"}}
console.log(Object.keys(messages).length) // 1
Or in your code:
...
.then((data) => {
this.messages = data.data
console.log(Object.keys(this.messages).length)
})

How to Improve The axios.spread

The below code i use for doing multiple HTTP calls depending on the studentList.
It works well; however, I think the axios spread is not necessary
export default {
getFee (studentList: { studentId: string }[]) {
if (studentList.length < 1) {
Promise.resolve()
}
let promises = []
for (const student of studentList) {
if (!student.studentId) {
Promise.resolve()
}
var url = `${API_URL}/${student.studentId}`
promises.push(Axios.get(url))
}
return Axios.all(promises)
.then(Axios.spread((...args) => {
// customise the response here
return args
.map(response => response.data)
.map(data => {
// #ts-ignore
data.totalMark = data.markinPhysics + data.markinMaths + data.markinChemistry // total mark sum of marks in differnet discplines
return data
})
}))
.catch(error => {
switch (error.response.status) {
case 400:
console.log('student not found')
break
case 500:
console.log('error invoking')
break
default:
console.log('unknown error')
I have to do multiple network calls in Vue and I am using Axios.
I got it working by axios, all and axios.spread, but I think the code can be improved.
The logic is to do multiple calls for the student list and get the outputs back
Can anyone help?
Axios.all
as well as Promise.all accepts array of promises and returns a new Promise which is resolved whenever all of the given promises are resolved with an array with the result of each promise
e.g.
const promise1 = Promise.resolve('data1');
const promise2 = Promise.resolve('data2');
Promise.all([
promise1,
promise2,
]).then(results => {
// results is an array with 2 elements
console.log(results[0]); // data1
console.log(results[1]); // data2
});
you can use Axios.spread to to assign each result to a variable like this:
Promise.all([
promise1,
promise2,
]).then(Axios.spread(( result1, result2 ) => {
// args is an array with 2 elements
console.log(result1); // data1
console.log(result2); // data2
});
alternatively you can use ES6 Destructuring assignment:
Promise.all([
promise1,
promise2,
]).then(([ result1, result2 ]) => {
// args is an array with 2 elements
console.log(result1); // data1
console.log(result2); // data2
});
Unnecessary Promise.resolve()
Your Promise.resolve() function calls have no effect on the getFee method since you're not returning them
What would my implementation be
async function getFee(studentList) {
try {
const promises = studentList.reduce((acc, student) =>
student.studentId
? acc.concat(Axios.get(`${API_URL}/${student.studentId}`))
: acc
, []);
const responses = await Axios.all(promises);
return responses
.map(response => response.data)
.map(data => ({
// return new object
// with data's properties
// instead of assinging the new ones directly to the data
...data,
// total mark sum of marks in differnet discplines
totalMark: data.markinPhysics + data.markinMaths + data.markinChemistry,
}));
} catch (error) {
switch (error.response.status) {
case 400:
console.log("student not found");
break;
case 500:
console.log("error invoking");
break;
default:
console.log("unknown error");
}
}
}
export default {
getFee
}
Since you're only using args as an array, you could remove axios.spread.
axios.spread() might only be useful in older browsers now that ES2015 introduced its own spread operator. The main purpose of axios.spread() is to expand the result of axios.all() into an argument list, such that you could do:
axios.all(promiseArray).then(axios.spread(function(arg1, arg2, arg3) {
/*...*/
}))
instead of:
axios.all(promiseArray).then(function(args) {
var arg1 = args[0]
var arg2 = args[1]
var arg3 = args[2]
/*...*/
})
ES2015's rest operator does the inverse of axios.spread(), so when you combine them (as seen below), you end up with the result above, as if axios.spread() and the rest operator weren't even used:
axios.all(promiseArray).then(axios.spread(function(...args) {
var arg1 = args[0]
var arg2 = args[1]
var arg3 = args[2]
/*...*/
}))
// or newer syntax:
axios.all(promiseArray).then(axios.spread((...args) => {
const arg1 = args[0]
const arg2 = args[1]
const arg3 = args[2]
/*...*/
}))
To avoid promise chaining and improve readability, I think below can be used.
const [arg1, arg2] = await Promise.all(promises)

Pg-promise : transaction issue

I got something strange with pg-promise with a transaction with generators.
This is what I want :
Get or register a user (getOrRegisterUser)
Do batch stuff (4 inserts generator)
Finally , do the last insert (generator registerCall) with the result of getOrRegisterCurrentParkingIfProvided generator
Here is my code :
db.tx(function (t) {
return t.task.call(params, getOrRegisterUser).then(function (user) {
params.masterId = user.id; // NOTICE : MY USER ID DATABASE
return t.batch([
t.task.call(params, registerNewPhones),
t.task.call(params, registerNewPlate),
t.task.call(params, registerNewSubscriptions),
t.task.call(params, getOrRegisterCurrentParkingIfProvided)
]).then(function (result) {
params.ParkingId = (result[3] !== undefined) ? result[3].id : null;
return t.task.call(params, registerCall);
})
});
}).then(function () {
// job done
resolve();
}).catch(function (err) {
console.log(err);
reject(err);
});
I got this error message at the second generator (registerNewPhones) :
severity: 'ERREUR',
code: '23503',
detail: 'La clé (customer)=(3) n\'est pas présente dans la table « users ».',
Any way to solve this ? I tried transactions like this : https://github.com/vitaly-t/pg-promise#nested-transactions or https://github.com/vitaly-t/pg-promise#synchronous-transactions but with some unknown circumstances I still got error somewhere.
Thanks
PS: I know that the implementation of these generators aren't guilty so ...
EDIT: if you really want to see the code
let squel = require('squel');
// squel with PostgresSQL syntax
let squelPostgres = squel.useFlavour('postgres');
registerNewPhones :
// Register all new phones numbers for user
function * registerNewPhones(t) {
let params = t.ctx.context;
let findPhonesForUserQuery = squelPostgres
.select()
.from("HELPDESK.phones")
.field("number")
.where("customer = ?", params.masterId)
.toString();
let registerPhoneForUser = squelPostgres
.insert()
.into("HELPDESK.phones")
.set("customer", params.masterId);
// find the already known phone number(s) for this user
return t.any(findPhonesForUserQuery).then(function (result) {
// data
let phones = (params.hasOwnProperty("phones") ? params.phones : []);
let alreadyRegisteredPhones = result.map(function (element) {
return element.number;
});
// filter data
let phonesToRegister = phones.filter(function (aPhoneNumber) {
return alreadyRegisteredPhones.indexOf(aPhoneNumber) == -1;
});
// create queries
let queries = phonesToRegister.map(function (phone) {
return db.none(
registerPhoneForUser
.clone()
.set("number", phone)
.toString()
);
});
return t.batch(queries);
});
}
and the generator getOrRegisterUser:
function * getOrRegisterUser(t) {
let params = t.ctx.context;
// QUERIES:
let findUserQuery = squelPostgres
.select()
.from("HELPDESK.users")
.field("id")
.where("registered_id = ?", params.userId)
.toString();
let insertUserQuery = squelPostgres
.insert()
.into("HELPDESK.users")
.setFields({
name: params.userName,
registered_id: params.userId,
typeOfAccount: 'BASIC',
email: params.email
})
.returning('id')
.toString();
let user = yield t.oneOrNone(findUserQuery);
return yield user || t.one(insertUserQuery);
}
The issue is within the ES6-Generator function registerNewPhones:
return t.any(findPhonesForUserQuery)...
it doesn't yield the promise result, which is required for ES6 Generator functions.
i.e. it must be:
return yield t.any(findPhonesForUserQuery)...

Angular http testing

I have a fairly simple controller that gets a simple json list of objects ...
function ProductGroupsCtrl($scope, $http, $routeParams, sharedService, popupService) {
$scope.list = null;
$scope.selectedItem = null;
$scope.selectedItemJsonString = '';
$scope.selectItem = function (item) {
$scope.selectedItem = item;
$scope.selectedItemJsonString = JSON.stringify(item);
//alert(JSON.stringify(item));
};
$scope.closePopup = function () {
$scope.selectedItem = null;
$scope.selectedItemJsonString = '';
};
// sharedService.prepForBroadcast($routeParams.anotherVar);
$http({
method: 'GET',
url: '/ProductGroup'
}).success(function (data) {
$scope.list = data;
}).
error(function (data) {
$scope.message = 'There was an error with the data request.';
});
}
I then try to mock the request in the test class:
var scope, ctrl, $httpBackend, sharedServiceMock = {}, popupServiceMock = {};
beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) {
$httpBackend = _$httpBackend_;
$httsypBackend.expectGET('/ProductGroup').
respond([{
ProductGroupID: 5,
MenuTitle: "Promotional Products",
AlternativeText: "Coming soon - a collection of environmentally friendly Promotional Products",
OrdinalPosition: 5,
Active: false
}]);
scope = $rootScope.$new();
ctrl = $controller(ProductGroupsCtrl, {
$scope: scope,
$http: $httpBackend,
sharedService: sharedServiceMock,
popupService: popupServiceMock
});}));
However I receive an error in the testacular window object undefined. What have I done wrong here?
Found the answer. If I remove the error callback function from the $http.get method then it works, i.e. remove the following ...
error(function (data) {
$scope.message = 'There was an error with the data request.';
}
I have to say Angular sure is a steep learning curve for someone who is not a day to day JavaScript programmer (although I seem to be doing more and more). Thanks for the help anyway KatieK :-)