Я пытаюсь просмотреть массив объектов и добавить к каждому свойство, соответствующее определенным критериям.

Вот фрагмент:

onRecordEditFormLoad(event)
{    
    let tempFieldWrapperArray = this.fieldSetWrapper.fieldWrappers.map(element => element);
    //console.log('onRecordEditFormLoad running: tempFieldWrapperArray',JSON.stringify(tempFieldWrapperArray));

    let tempInputFieldArray = [];
    this.template.querySelectorAll('lightning-input-field').forEach(inputField => { 
        tempInputFieldArray.push({"fieldName":inputField.fieldName , "value":inputField.value});
    });
    console.log('onRecordEditFormLoad running: tempInputFieldArray',JSON.stringify(tempInputFieldArray));

    tempFieldWrapperArray.forEach(fieldWrapper => {
        let inputField = tempInputFieldArray.find(inputField => inputField.fieldName === fieldWrapper.fieldAPIName);
        console.log('onRecordEditFormLoad running: tempFieldWrapperArray: inputField',JSON.stringify(inputField)); 
        if(inputField){
            console.log('inputField.value',inputField.value);
            console.log('fieldWrapper',fieldWrapper);
            fieldWrapper.value = inputField.value;
        }
    });
    console.log('onRecordEditFormLoad running: tempFieldWrapperArray',JSON.stringify(tempFieldWrapperArray)); 
}

Код перестает работать, когда он добавляет свойство: fieldWrapper.value = inputField.value;

Объект fieldWrapper и inputField.value допустимы и регистрируются. Если я закомментирую fieldWrapper.value = inputField.value, остальная часть кода запустится.

0
Gabriel Rivera 1 Июл 2020 в 22:44
Какую ошибку вы получаете в консоли браузера при выполнении оскорбительного кода?
 – 
Phil W
1 Июл 2020 в 22:46
Нет ошибки. Код просто перестает работать после этой строки.
 – 
Gabriel Rivera
1 Июл 2020 в 22:48
(См. ответ sfdcfox; в основном результаты проводного и императивного классов заморожены (с использованием Object.freeze или аналогичный), что означает, что вам необходимо клонировать объекты, прежде чем вы сможете изменять клоны.)
 – 
Phil W
1 Июл 2020 в 22:53

2 ответа

Лучший ответ

Предполагая, что это произошло из-за вызова сервера, вам нужно полностью скопировать объекты:

let tempFieldWrapperArray = this.fieldSetWrapper.fieldWrappers.map(element => ({...element}));

Или же:

let tempFieldWrapperArray = this.fieldSetWrapper.fieldWrappers.map(element => Object.assign({},element));

Это связано с тем, что весь ответ заблокирован ReadOnlyMembrane, который предотвращает изменение, чтобы кеш не мог не быть поврежденным ссылками.

Копируя элементы с помощью оператора распространения (...) или Object.assign в новый объект, вы удаляете свойства только для чтения всех элементов верхнего уровня.

3
sfdcfox 1 Июл 2020 в 23:11
1
Не могли бы вы обновить свой ответ, чтобы указать, что объекты, полученные с сервера, «заморожены» и поэтому неизменны. В этот момент клонирование имеет абсолютный смысл. Я ожидаю, что это будет обработано с помощью Object.freeze.
 – 
Phil W
1 Июл 2020 в 22:57
Хорошая точка зрения.
 – 
sfdcfox
1 Июл 2020 в 23:03
Хороший. Как насчет добавления ссылки на github.com/salesforce/observable-membrane, которая включает раздел, посвященный только для чтения и, по-видимому, является частью инфраструктуры Salesforce (обратите внимание, что Кевин Хилл внес свой вклад).
 – 
Phil W
1 Июл 2020 в 23:08
let tempFieldWrapperArray = this.fieldSetWrapper.fieldWrappers.map(element => element);

Здесь вы просто назначаете новую ячейку памяти переменной массива. Но Javascript выделяет отдельную память для основного массива и элементов внутри него (если они являются объектами).

Из документации:

Непримитивное значение (например, объект или массив), передаваемое компоненту, доступно только для чтения. Компонент не может изменить содержимое объекта или массива. Если компонент попытается изменить содержимое, вы увидите ошибку в консоли браузера. Чтобы изменить данные, сделайте поверхностную копию объектов, которые вы хотите изменить.

Таким образом, объект, возвращенный напрямую или в массиве, будет в неизменном/замороженном состоянии. Вы увидите журналы отладки в консоли, когда включите режим отладки для компонентов Lightning

Вам нужно вернуть новую копию для каждого объекта внутри массива, поскольку каждый из них неизменяем.

tempFieldWrapperArray = tempFieldWrapperArray.map(fieldWrapper => {
    fieldWrapper = {...fieldWrapper};
    -- code --
        fieldWrapper.value = inputField.value;
    
    return fieldWrapper;
});
2
salesforce-sas 1 Июл 2020 в 23:16
Это не объясняет ясно проблему - если я скопирую/вставлю два ваших оператора, я МОГУ успешно их запустить.
 – 
Phil W
1 Июл 2020 в 22:56
Вы не можете, если arr является переменной API и передается ей
 – 
salesforce-sas
1 Июл 2020 в 22:57
Я предлагаю вам уточнить, что вы имеете в виду аннотированный @api. Да, это снова верно, потому что структура LWC гарантирует, что такие значения будут заморожены.
 – 
Phil W
1 Июл 2020 в 22:58
2
Можете ли вы добавить объяснение, почему объекты в массиве неизменяемы, пожалуйста.
 – 
Phil W
1 Июл 2020 в 23:01
1
В основном добавьте что-то вроде «Объекты, полученные в LWC либо через свойство @api, либо по проводу, либо по императивному вызову сервера, неизменяемы (вероятно, с использованием Object.freeze)».
 – 
Phil W
1 Июл 2020 в 23:02