Lightning 웹 Components(LWC)에서 요소를 동적으로 추가/제거하는 버튼 설치
91991 단어 SalesforceAPEXlwcsfdxappExchangetech
무슨 물건이요?
사용자 정의 구성 요소를 만들고 동적 추가(+) 또는 삭제(-) 대상 항목을 위한 단추를 만듭니다.
기본적으로 준비된 구성 요소
사용자 정의 항목의 내용을 동적으로 추가하거나 삭제할 수 없기 때문에 실현할 수 있습니다.
재료 분산
메커니즘으로 JSON 문자열이 변환된 데이터만 사용자 정의 항목(데이터 유형: 긴 텍스트 영역)에 저장합니다.간단하다
따라서 대상의 모든 항목명 취득과 lwc의 특수문법 해설도 함께 넣는다.
(1) 사용자 정의 항목 추가
사용자 정의 구성 요소의 대상에 새 사용자 정의 항목을 추가합니다.
sfdx force:org:open -u <username/alias>
sfdx force:source:pull -u <username/alias>
데이터 내용을 확인/표시하려면 검사를 취소하지 않아도 됩니다.
(2) 권한 집합의 (1) 허용
AppExchange에서 새로운 프로젝트를 개발할 때 잊어버리기 쉬운 프로젝트입니다.
sfdx force:org:open -u <username/alias>
sfdx force:source:pull -u <username/alias>
(3) 서버측 개발(classes)
사용자 정의 구성 요소의 뒷면을 만들다.apex로 클래스를 만듭니다.
디렉토리 구성은 다음과 같습니다.
root
└── force-app
└── main
└── default
└── classes
├── [クラス名].cls
├── [クラス名].cls-meta.xml
├── [クラス名]_Test.cls
└── [クラス名]_Test.cls-meta.xml
예를 들어 프로젝트 덮어쓰기 규칙을 동적으로 추가/삭제하는 구성 요소를 만듭니다.Read, Consulting, Partner, Partner Driven 등 4개 객체에 대한 업데이트 가능한 항목을 모두 가져오고 나열하여 덮어쓰기 규칙을 선택/작성할 수 있습니다.
apex API 버전 v510
[학급 이름]cls
***
... (1) 의 새 항목을 포함하는 개체 API 참조 이름$$$
... (1) 의 새 항목 이름각각 교체하십시오.
[학급 이름]cls
public with sharing class [クラス名] {
// 「リード」「商談」「取引先」「取引先責任者」のオブジェクトリスト
static final List<String> OBJECTS_LIST = new List<String>{
'Lead', 'Opportunity', 'Account', 'Contact'
};
public static List<***> getRecord(id recId) {
return [SELECT $$$ FROM *** WHERE id =: recId];
}
@AuraEnabled(cacheable=true)
public static String getRules(id recId) {
*** record = getRecord(recId)[0];
if (record.$$$ != null) { return record.$$$; }
return '[]';
}
@AuraEnabled
public static Integer updateRules(id recId, String newRules) {
try {
if (newRules.length() > 13107) { return 400; }
List<Object> overwriteInfo = (List<Object>)JSON.deserializeUntyped(newRules);
for (Object info: overwriteInfo){
Map<String, Object> infoMap = (Map<String, Object>)info;
List<String> objValue1 = ((String)(infoMap.get('objValue1'))).split(':');
List<String> objValue2 = ((String)(infoMap.get('objValue2'))).split(':');
if (objValue1.size() != 2 || objValue2.size() != 2 || objValue1 == objValue2) { return 400; }
Schema.DisplayType v1 = getTypeByObjField(objValue1[0], objValue1[1]);
Schema.DisplayType v2 = getTypeByObjField(objValue2[0], objValue2[1]);
if (v1 != v2) { return 400; }
}
List<test_iijima__TEST__c> records = getRecord(recId);
records[0].test_iijima__Rules__c = newRules;
update records;
return 200;
} catch(DmlException e) {
return 500;
}
}
public static Schema.DisplayType getTypeByObjField(String objName, String fieldName) {
return Schema.getGlobalDescribe().get(objName).getDescribe().fields.getMap().get(fieldName).getDescribe().getType();
}
@AuraEnabled(cacheable=true)
public static Map<String, List<ApiLabelValue>> getObjFeildList(id recId) {
Map<String, List<ApiLabelValue>> result = new Map<String, List<ApiLabelValue>>();
for (String objName: OBJECTS_LIST){
sObject sObj = getSObject(objName);
result.put(objName, getApiLabelValue(sObj));
}
return result;
}
public static sObject getSObject(String objName) {
return Schema.getGlobalDescribe().get(objName).newSObject();
}
public static DescribeSObjectResult getSObjectDescribe(sObject sObj) {
return sObj.getSObjectType().getDescribe();
}
public static List<ApiLabelValue> getApiLabelValue(sObject sObj) {
DescribeSObjectResult sObjectDescribe= getSObjectDescribe(sObj);
Map<String, SObjectField> sObjectFields = sObjectDescribe.fields.getMap();
String objName = sObjectDescribe.getName();
String objLabel = sObjectDescribe.getLabel();
List<ApiLabelValue> result = new List<ApiLabelValue>{};
for(SObjectField f : sObjectFields.values()) {
DescribeFieldResult field = f.getDescribe();
if (field.isUpdateable()) {
String label = '【' + objLabel + '】' + field.getLabel();
String value = objName + ':' + field.getName();
ApiLabelValue fields = new ApiLabelValue(label, value);
result.add(fields);
}
}
return result;
}
public class ApiLabelValue{
@AuraEnabled
public String label;
@AuraEnabled
public String value;
public ApiLabelValue(String l, String v) {
label = l; value = v;
}
}
}
[학급 이름]cls-meta.xml[학급 이름]cls-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
해설
@AuraEnabled
이 초대장을 지정하면 lwc(전면)에서 사용할 수 있습니다.
updateRules(id recId, String newRules)
JSON 문자열 데이터(newRules)를 정면에서 보내는 것은 검증과 업데이트 처리를 실시하는 방법이다.
발리 2일을 실시했다.
JSON 문자열 데이터는 긴 텍스트 영역 유형(((1)에 저장되므로 최대 길이인 1317보다 작아야 합니다.
newRules.length() > 13107
이번 예는 프로젝트 간의 덮어쓰기 규칙을 추가/삭제하기 때문에 프로젝트 유형이 같지 않으면 덮어쓸 수 없습니다.
따라서
getTypeByObjField(String objName, String fieldName)
에서 항목 유형을 취득하고 동일 여부를 확인한다.Salesforce에서 제공하는 대상 조회 언어인'soql'은
Select * From [オブジェクトAPI参照名]
등 모든 데이터를 사용할 수 없습니다.그래서 모든 데이터가 아니라 모든 프로젝트 이름을 얻으려고 할 때 사용하는 방법을 실현했다.
field.isUpdateable()
업데이트 가능한 항목만 가져옵니다.반환 값은 (4) lwc에서 사용하는 지정한 형식 (ApiLabelValue) 을 임의로 명명하여 이루어진 것입니다.
오류 반환값과 검증은 필요한 최소한으로만 이루어집니다. 필요하면 추가/수정하십시오.
잊지 마라
스크래치 조직을 미리 변경
sfdx force:source:push -u <username/alias>
(4) 프론트 데스크톱 개발(lwc)
사용자 정의 구성 요소의 외관을 만듭니다.
디렉토리 구성은 다음과 같습니다.
root
└── force-app
└── main
└── default
└── lwc
└── [カスタムコンポーネント名]
├── [カスタムコンポーネント名].css
├── [カスタムコンポーネント名].html
├── [カスタムコンポーネント名].js
└── [カスタムコンポーネント名].js-meta.xml
버튼의 수량은 1~50 이내로 제한됩니다.(js 참조)lwc API 버전 v51.0
[구성 요소 이름 사용자 정의]css
[구성 요소 이름 사용자 정의]css
.component {
background-color:white;
text-align: center;
padding: 20px 0;
border-radius: 5px;
}
.left {
text-align: left;
margin-left:10px;
}
.title {
margin:10px 0;
padding-left:10px;
text-align: left;
font-size: 15px;
color: #222222;
}
.error {
color: red;
}
.select {
text-align: left;
display: inline-block;
width: 40%;
}
.arrow {
display: inline-block;
margin: 0 1%;
}
.button {
margin-left: 1%;
}
[구성 요소 이름 사용자 정의]html[구성 요소 이름 사용자 정의]html
<template>
<div class="component">
<p class="title">上書きルールの設定</p>
<template if:true={hasError}>
<p class="error">{errorMsg}</p>
</template>
<div class="left">
<template iterator:it={rules}>
<lightning-combobox
key={it.value.objValue1}
class="select"
label=""
value={it.value.objValue1}
placeholder="選択してください"
options={objFeildList}
onchange={changeObjFeildList1}
data-index={it.index} >
</lightning-combobox>
<lightning-icon
key={it.value.objValue1}
class="arrow"
icon-name="utility:forward" >
</lightning-icon>
<lightning-combobox
key={it.value.objValue1}
class="select"
label=""
value={it.value.objValue2}
placeholder="選択してください"
options={objFeildList}
onchange={changeObjFeildList2}
data-index={it.index} >
</lightning-combobox>
<template if:false={isDataSizeMin}>
<lightning-button-icon
key={it.value.objValue1}
variant="bare"
data-index={it.index}
icon-name="utility:ban"
onclick={clickDelete}
alternative-text="delete"
class="button" >
</lightning-button-icon>
</template>
<template if:false={isDataSizeMax}>
<template if:true={it.last}>
<lightning-button-icon
key={it.value.objValue1}
variant="bare"
data-index={it.index}
icon-name="utility:new"
onclick={clickAdd}
alternative-text="add"
class="button" >
</lightning-button-icon>
</template>
</template>
<br key={it.value.objValue1}>
</template>
</div>
<br>
<lightning-button
variant="brand"
label="保存"
onclick={clickSave}
disabled={noEdited} >
</lightning-button>
</div>
</template>
[구성 요소 이름 사용자 정의]js[구성 요소 이름 사용자 정의]js
import {LightningElement, api, wire, track} from 'lwc';
//[クラス名]は(3)で作成したapexクラス名です
import getObjFeildList from '@salesforce/apex/[クラス名].getObjFeildList';
import getRules from '@salesforce/apex/[クラス名].getRules';
import updateRules from '@salesforce/apex/[クラス名].updateRules';
export default class CustomComponent extends LightningElement {
@api recordId;
@track rules;
@track objFeildList;
@wire(getObjFeildList)
wiredObjFeildList({ error, data }) {
if (data) {
this.objFeildList = [
{"objValue1":"", "objValue2":"","label":"選択してください"},
...data.Lead,
...data.Opportunity,
...data.Account,
...data.Contact,
];
} else if (error) {
console.log(JSON.stringify(error, null, '\t'));
}
}
@wire(getRules, {recId: '$recordId'})
wiredRules({ error, data }) {
if (data) {
var savedRules = JSON.parse(data);
if (savedRules.length != 0) {
this.rules = savedRules;
} else {
this.rules = [{"objValue1":"", "objValue2":""}];
}
} else if (error) {
console.log(JSON.stringify(error, null, '\t'));
}
}
@track noEdited = true;
@track hasError = false;
@track errorMsg = "";
get isDataSizeMin() {
return this.rules.length <= 1 ? true : false;
}
get isDataSizeMax() {
return this.rules.length > 50 ? true : false;
}
changeObjFeildList1(e) {
this.rules[+e.target.dataset.index].objValue1 = e.detail.value;
this.noEdited = false;
}
changeObjFeildList2(e) {
this.rules[+e.target.dataset.index].objValue2 = e.detail.value;
this.noEdited = false;
}
clickAdd() {
this.rules.push({"objValue1":"", "objValue2":""});
this.noEdited = false;
}
clickDelete(e) {
if (this.rules.length == 1) {
this.clickAdd();
} else {
this.rules.splice(+e.target.dataset.index, 1);
this.noEdited = false;
}
}
clickSave() {
this.hasError = false;
let keys = [];
let savedRules = JSON.parse(JSON.stringify(this.rules));
if (!savedRules || savedRules.length == 1 && !savedRules[0].objValue1 && !savedRules[0].objValue2) {
savedRules = [];
}
savedRules.forEach( v => {
if (!v.objValue1 || !v.objValue2) {
this.hasError = true;
this.errorMsg = "空欄があります。";
} else if (v.objValue1 == v.objValue2) {
this.hasError = true;
this.errorMsg = "同じ項目を選択しています。";
} else {
keys.push(v.objValue1 + v.objValue2);
}
});
if (this.hasError) { return; }
if ((new Set(keys)).size != savedRules.length) {
this.hasError = true;
this.errorMsg = "ルールが重複しています。";
return;
}
savedRules = JSON.stringify(savedRules);
if (savedRules.length > 131072) {
this.hasError = true;
this.errorMsg = "ルールをこれ以上追加できません。";
return;
}
updateRules({ recId: this.recordId, newRules: savedRules })
.then(result => {
if (result == 200) {
location.reload();
} else if (result == 400) {
this.hasError = true;
this.errorMsg = "ルールのデータ型が異なります。";
} else {
this.hasError = true;
this.errorMsg = "ルールを追加できませんでした。";
}
});
}
}
[구성 요소 이름 사용자 정의]js-meta.xml[구성 요소 이름 사용자 정의]js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__RecordPage</target>
</targets>
</LightningComponentBundle>
해설
HTML 템플릿(if)
lwc의 HTML 템플릿에서if 문을 처리할 수 있습니다.
하지만 연산자사용할 수 없습니다.
이를 위해 js 측에서 진위 값의 속성 값을 되돌려 주려고 합니다.
예제
<!-- if true -->
<template if:true={hasError}>
...
</template>
<!-- if false -->
<template if:false={isDataSizeMin}>
...
</template>
HTML 템플릿lwc의 HTML 템플릿에서 두 가지 중복 처리를 처리할 수 있습니다.
데이터 예
values = [
{ Id: 1, Name: 'a', Title: 'A' },
{ Id: 2, Name: 'b', Title: 'B' },
{ Id: 3, Name: 'c', Title: 'C' },
];
for:each
for:index="index"
를 사용하여 현재 항목의 인덱스에 액세스합니다.<template for:each={values} for:item="value">
<li key={value.Id}>
{value.Name}, {value.Title}
</li>
</template>
iterator
forEach보다 사용이 편리한 것은iterator입니다.
value
, index
이외first
... Boolean 값last
... 이 항목이 목록의 마지막 항목인지 여부를 표시하는 Boolean 값네.
처리의 시작과 마지막에 디스플레이를 바꾸고 싶을 때 연산자를 사용할 수 없는if문장과 함께 사용할 수 있습니다.
이번 구현 방식은 요소 추가/삭제 버튼을 통해 마지막 요소인'+'버튼만 설정하거나 요소가 하나일 때'-'버튼의 표시
first
와 last
를 없애는 것이 중요하다.<template iterator:it={values}>
<li key={it.value.Id}>
<div if:true={it.first} class="list-first"></div>
{it.value.Name}, {it.value.Title}
<div if:true={it.last} class="list-last"></div>
</li>
</template>
목록의 모든 항목은 key
을 포함해야 합니다.key
는 문자열이나 숫자여야 하지만 index는 키 값으로 사용할 수 없습니다.lwc 라이브러리 (@api, @track, @wire)
@api
공통 속성.화면의 변경을 감지하여 처리하다.
클래스에서 선언
@api recordId
은 현재 레코드 ID를 자동으로 가져옵니다.@track
이것은 개인 속성이다.화면의 변경을 감지하여 처리하다.
@wire
자바스크립트의 변수와 Apex 방법을 연결합니다.매개 변수는 대상을 통해 전달된다.
예제
import {LightningElement, api, wire, track} from 'lwc';
import [メソッド名] from '@salesforce/apex/[クラス名].[メソッド名]';
export default class [クラス名] extends LightningElement {
@api recordId;
@track data;
@wire([メソッド名], {recId: '$recordId'})
wiredRules({ error, data }) {
if (data) {
this.data = data;
} else if (error) {
console.log(JSON.stringify(error, null, '\t'));
}
}
...
}
필요한 최소한의 검증만 실시했기 때문에 필요하면 추가/수정해 주십시오.잊지 마라
스크래치 조직을 미리 변경
sfdx force:source:push -u <username/alias>
(5) 레이아웃에 사용자 정의 구성 요소 추가
(3) 스크래치 조직에 (4)를 넣으면 페이지 편집에서 사용자 정의 구성 요소를 추가할 수 있습니다.
sfdx force:org:open -u <username/alias>
sfdx force:source:pull -u <username/alias>
완성!
기본적으로 준비된 구성 요소 종류는 다양하지만 없는 게 없으니 직접 해보세요.
alesforce가 독자적으로 제공하는 특수 문법을 익히면 할 수 없는 것이 없다.
그리고 AppExchange 개발이 할 수 있는 일의 폭을 늘렸어요!
Reference
이 문제에 관하여(Lightning 웹 Components(LWC)에서 요소를 동적으로 추가/제거하는 버튼 설치), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/cahchachakari/articles/7ee56778e73de8텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)