2

I have two @wired methods - how can I calculate a value in one method and then use it in the second method? I know everything is reactive - so I'm sure this is a somewhat stupid question but I just can't seem to find an answer to this.

import { api, LightningElement, wire } from 'lwc';
import { getRecord } from "lightning/uiRecordApi";
import fetchData from '@salesforce/apex/MyController.fetchData';

export default class MyElement extends LightningElement {
    @api recordId;

    // dependent value
    someValue;

    @wire(getRecord, { recordId: '$recordId' })
    wiredRecord({ error, data }) {
        if (data) {
            this.someValue = 'Test';
        } else if (error) {
            console.error('Error fetching data:', error);
        }
    }

    @wire(fetchData, { $recordId: '$recordId' })
    wiredData({ error, data }) {
        if (data) {
            console.log(this.someValue); // This will be empty!
        } else if (error) {
            console.error('Error fetching data:', error);
        }
    }
}

This is of course a simplified example - but I do calculate some data based on the record itself via getRecord and then call my custom apex method fetchData to calculate the rest. My actual example creates markers for a lightning-map where I have some data in the record itself and most of the data somewhere else. Maybe this helps with understanding my use case better without making my actual example more complicated.

And if this is somewhat a stupid question - please help me improve it. :)

2
  • 1
    Did you try passing someValue as a parameter. Something similar is answered here Commented Apr 5 at 18:35
  • I did not because someValue is not a parameter of fetchData. I'll check your link nonetheless. Thanks!
    – Semmel
    Commented Apr 5 at 18:42

1 Answer 1

2

In the general sense, just add a method that does the calculation, and call it from both places:

@api recordId;
someValue1;
someValue2;
@wire(getRecord, { recordId: '$recordId' }) handleGetRecord({ data, error }) {
  if(data) {
    this.someValue1 = data;
    this.doProcessing();
  }
  if(error) {
    this.handleError(error);
  }
}
@wire(fetchData, { recordId: '$recordId' }) handleFetchData({data, error}) {
  if(data) {
    this.someValue2 = data;
    this.doProcessing();
  }
  if(error) {
    this.handleError(error);
  }
}
doProcessing() {
  if(!this.someValue1 || !this.someValue2) {
    return;
  }
  // Do rest of processing
}

Alternatively, use imperative calls instead of wire, if that makes more sense:

async connectedCallback() {
  const recordId = this.recordId;
  this.someValue1 = await getRecord({recordId});
  this.someValue2 = await fetchData({recordId});
  this.doProcessing();
}

Or, if you expect that recordId might change, you can even use a getter/setter pattern:

#recordId;
@api set recordId(value) {
  this.#recordId = value;
  this.getAndFetch();
}
get recordId() {
  return this.#recordId;
}
async getAndFetch() {
  const recordId = this.#recordId;
  this.someValue1 = await getRecord({recordId});
  this.someValue2 = await fetchData({recordId});
  this.doProcessing();
}

The # simply indicates that this is a private field (it can't be used outside the class).

5
  • 1
    Maybe this is just a more complex example of how these concepts work together - but so far I couldn't find it in a single place used all at once. So this is a great example of combining all of this and keeping it clean. Thanks!
    – Semmel
    Commented Apr 10 at 0:29
  • 1
    @Semmel You're welcome!
    – sfdcfox
    Commented Apr 10 at 1:54
  • Not sure this should be a new question but - now I have the problem that under some circumstances the methods trigger in the "wrong" order and I need some of the data from one method already present in the second method. Is there a way to get this to work without imperative calls?
    – Semmel
    Commented Apr 23 at 20:57
  • 1
    @Semmel Yes. Use a separate variable, and set it. Wire calls don't fire until the value isn't undefined: @api recordId; recordId2; @wire(f1, { recordId: '$recordId' }) fn1(res) { if(res.data) { this.recordId2 = res.data.whatever; } } @wire(f2, { recordId: '$recordId2' }) fn2(res) { ... }
    – sfdcfox
    Commented Apr 23 at 21:40
  • That's genius! It looks a little bit weird but in my case, in particular, it works quite well as the first parameter to the second function is called opportunityId anyway! I do find it a little bit non-obvious when reading the code so in my case I wrote a short comment explaining the rationale behind it. Thanks for this neat little tip!
    – Semmel
    Commented Apr 24 at 11:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .