英文:
Template data displayed is not refreshing after onchnage event of a custom picklist field using In Salesforce LWC
问题
I am displaying records in html template using LWC in salesforce. My columns containing depended fields like country, state, and city. When I am modifying displayed data by changing the country, then I need to get dependent states in my State Picklist.
Salesforce Implementation
These picklists, say country, state, and city that I used here are implemented using custom picklist field method using LWC components. When Component loads the first time, I am looping all the records directly from the related tables.
And after loading records, If I am changing the country, I implemented onchange method which will load all related states of that selected country. Here from my onchange method I am able to pull all related states and able to update to looping data this.sDetails. But the problem is looping data not refreshing after onchange. Here I need to get refreshed and modified data after the onchange method.
onchange code from .js file
handleCountryChangeEvent(event) {
const selectedCountryValue = event.detail;
for (var i = 0; i < this.countryOptions.length; i++) {
if (this.countryOptions[i].label == selectedCountryValue) {
var key = i;
}
}
this.allStateOptions = this.allStateOptions
.filter(option => option.validFor.includes(key));
this.sDetails.forEach(ele => {
ele.stateOptionsList = this.allStateOptions;
})
console.log(this.sDetails);
refreshApex(this.sDetails);
}
Defined Field in .js file,
{
label: 'State',
fieldName: 'state__c',
name: 'State',
placeholder: 'Choose State',
type: 'statePicklist',
typeAttributes: {
value: { fieldName: 'state__c' },
options: { fieldName: 'stateOptionsList' },
},
editable: true,
wrapText: true,
context: { fieldName: 'Id' }
},
Code for getting SDetails,
@wire(getStockDetails, { pickList: '$countryOptions' })
result(result) {
let sDetailsRObj = JSON.parse(JSON.stringify(result));
this.sDetails = stockDetailsRObj.data;
try {
this.sDetails.forEach(ele => {
ele.countryOptionsList = this.countryOptions;
ele.stateOptionsList = this.allStateOptions;
ele.cityOptionsList = this.cityOptions;
})
} catch (err) {
console.log(err.message);
}
}
Code for getting state and country picklists from .js file,
@wire(getPicklistValues,
{ recordTypeId: "$objectInfo.data.defaultRecordTypeId", fieldApiName: countryField })
wireCountryPickList({ error, data }) {
if (data) {
this.countryOptions = data.values;
}
else if (error) {
console.log(error);
}
}
@wire(getPicklistValues,
{
recordTypeId: "$objectInfo.data.defaultRecordTypeId",
fieldApiName: stateField
})
wireStatePickList({ error, data }) {
if (data) {
this.allStateOptions = data.values;
}
else if (error) {
console.log(error);
}
}
Problem Identified
Here I am properly getting all the states related to the selected country and able to properly bind to my looping data this.sDetails. But here after getting data on this.sDetails, the displayed data is not refreshing. Here the first time all data loads successfully, and after the country change, related states are getting in onchange method and loading to looping data. But it's not refreshing and not showing updated state options while displaying.
In my case, looping data not refreshing after the onchange event on the picklist field. Can please anyone guide me to resolve this issue or suggest any documentation to refer field dependency updation?
英文:
I am displaying records in html template using LWC in salesforce. My columns containing depended fields like country , state and city. When I am modifying displayed data by changing country, then I need to get depended states in my State Picklist.
Salesforce Implementation
These picklist , say country, state and city that I used here are implemented using custom picklist field method using LWC components. When Component loads first time, I am looping all the records directly from the related tables.
And after loading records, If I am changing country, I implemented onchange method which will load all related states of that selected country. Here from my onchange method I am able to pull all related states and able to update to looping data this.sDetails. But problem is looping data not refreshing after onchnage. Here I need to get refreshed and modified data after onchnage method
onchnage code from .js file
handleCountryChangeEvent(event) {
const selectedCountryValue = event.detail;
for(var i=0; i< this.countryOptions.length;i++){
if(this.countryOptions[i].label == selectedCountryValue){
var key = i;
}
}
this.allStateOptions = this.allStateOptions
.filter(option => option.validFor.includes(key));
this.sDetails.forEach(ele => {
ele.stateOptionsList = this.allStateOptions;
})
console.log(this.sDetails);
refreshApex(this.sDetails);
}
Defined Field in .js file,
{
label : 'State',
fieldName: 'state__c',
name : 'State' ,
placeholder : 'Choose State',
type: 'statePicklist',
typeAttributes: {
value: { fieldName: 'state__c' },
options: { fieldName: 'stateOptionsList' },
},
editable: true,
wrapText:true,
context: { fieldName: 'Id' }
},
Code for getting SDetails ,
@wire(getStockDetails, { pickList: '$countryOptions' })
result(result){
let sDetailsRObj = JSON.parse(JSON.stringify(result));
this.sDetails = stockDetailsRObj.data;
try
{
this.sDetails.forEach(ele => {
ele.countryOptionsList = this.countryOptions;
ele.stateOptionsList = this.allStateOptions;
ele.cityOptionsList = this.cityOptions;
})
}
catch(err) {
console.log(err.message);
}
}
Code for getting state and country picklists from .js file,
@wire(getPicklistValues,
{recordTypeId: "$objectInfo.data.defaultRecordTypeId",fieldApiName: countryField})
wireCountryPickList({ error, data })
{
if (data) {
this.countryOptions = data.values;
}
else if (error) {
console.log(error);
}
}
@wire(getPicklistValues,
{
recordTypeId: "$objectInfo.data.defaultRecordTypeId",
fieldApiName: stateField
})
wireStatePickList({ error, data })
{
if (data) {
this.allStateOptions = data.values;
}
else if (error) {
console.log(error);
}
}
Problem Identified
Here I am properly getting all the states related to selected country and able to properly bind to my looping data this.sDetails. But here after getting data on this.sDetails , the displayed data is not refreshing.
Here first time all data loads successfully, And after country change, related states are getting in onchnage method and loading to looping data. But its not refreshing and not showing updated state options while displaying.
In my case looping data not refreshing after onchnage event on picklist field. Can please anyone to guide me to resolve this issue or suggest any documentation to refer field dependency updation ?
答案1
得分: 1
可能导致模板不重新渲染以反映这些更改的一个可能原因是LWC(Lightning Web Components)框架可能未检测到您正在修改的属性的更改。
截至Spring '20发布,在检测数组和普通对象属性的更改方面,不再需要使用@track
装饰器。这是因为Lightning Web Components(LWC)引擎现在默认将这些类型的属性设为响应式。
然而,仍然需要注意的是,LWC引擎会跟踪属性本身的更改,但不一定会跟踪对象或数组中的深层嵌套更改。
如果您对对象的嵌套属性或数组中的元素进行更改,最好创建该对象或数组的新实例以确保更改被捕捉。
当您更新数组或对象时,创建该数组或对象的新实例,以便LWC可以识别更改:
this.sDetails = this.sDetails.map(detail => ({
...detail,
stateOptionsList: this.allStateOptions
}));
这种方法创建了一个包含更新的stateOptionsList
属性的新数组对象。这更有可能触发LWC的响应系统,并导致组件重新渲染以显示更新后的数据。
最后,您在代码中使用了refreshApex
,但似乎没有正确使用它。 refreshApex
用于刷新通过@wire
适配器检索的数据缓存。您必须将原始的@wire
属性传递给refreshApex
,而不是修改后的数据(参见“在LWC中使用refreshApex功能”)。
例如:
import { refreshApex } from '@salesforce/apex';
// ...
@wire(getStockDetails, { pickList: '$countryOptions' })
wiredStockDetails(result) {
this.wiredResult = result;
// ... 代码的其余部分
}
// 然后在您的handleCountryChangeEvent中
refreshApex(this.wiredResult);
作为最后的手段,用于测试,您可以通过更改某些状态来强制渲染,您知道这将导致组件重新渲染。
this.timestamp = new Date();
然后在您的模板中,将此属性绑定到某个隐藏字段或以某种方式使用它,以强制重新渲染。
英文:
One possible reason the template is not re-rendering to reflect these changes could be due to the fact that the LWC (Lightning Web Components) framework may not be detecting the change in the properties that you are modifying.
As of Spring '20 release, the use of the @track
decorator is no longer necessary for detecting changes in the properties of arrays and plain objects. This is because the Lightning Web Components (LWC) engine now defaults to making these types of properties reactive.
However, it is still important to note that the LWC engine tracks changes to the property itself, but not necessarily deeply nested changes within objects or arrays.
If you are making changes to nested properties of an object or elements within an array, it is best to create a new instance of the object or array to ensure that the changes are picked up.
When you are updating an array or an object, create a new instance of that array or object so that LWC can recognize the change:
this.sDetails = this.sDetails.map(detail => ({
...detail,
stateOptionsList: this.allStateOptions
}));
This approach creates a new array with new objects that include the updated stateOptionsList
property. It is more likely to trigger the reactivity system of LWC and cause the component to re-render with the updated data.
Finally, you are using refreshApex
in your code, but it seems that you are not using it properly. refreshApex
is used to refresh the cache of data retrieved via a @wire
adaptor. You must pass the original @wire
property to refreshApex
and not the modified data (see "working with the refreshApex feature in LWC").
For example:
import { refreshApex } from '@salesforce/apex';
// ...
@wire(getStockDetails, { pickList: '$countryOptions' })
wiredStockDetails(result) {
this.wiredResult = result;
// ... rest of the code
}
// Later in your handleCountryChangeEvent
refreshApex(this.wiredResult);
As a last resort, for testing, you can force a render by changing some state that you know will cause the component to re-render.
this.timestamp = new Date();
Then in your template, bind this property to some hidden field or use it in such a way that it forces a re-render.
答案2
得分: 0
当您尝试将对象或列表分配给当前的 LWC 属性时,您正在改变属性指向的 HTML,这会使属性与 HTML 断开连接,不会再重新渲染。
尝试更改此赋值:
this.allStateOptions = this.allStateOptions
.filter(option => option.validFor.includes(key));
为:
this.allStateOptions = [...this.allStateOptions
.filter(option => option.validFor.includes(key))];
英文:
When you try to assign an object or list to the current lwc property, you are changing the pointer of the property that the HTML attached to, which makes the property disconnect from the HTML and not rerender again.
try to change this assignment:
this.allStateOptions = this.allStateOptions
.filter(option => option.validFor.includes(key));
to:
this.allStateOptions = [...this.allStateOptions
.filter(option => option.validFor.includes(key))];
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论