Salesforce Lightning开发学习重写新建/更新按钮
Posted luqinghua
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Salesforce Lightning开发学习重写新建/更新按钮相关的知识,希望对你有一定的参考价值。
重写新建/更新按钮的原因是因为项目需要用户在新建数据时从接口对数据进行校验,保证数据的有效性,同时获取接口返回的部分数据完成信息填充,而Sales force的trigger仅支持@future方法异步调用接口,不能实时完成数据校验
那么重写新建/更新按钮要面临的几个核心问题:
1、lightning暂时不支持lookup字段,如果重写可能要自定义组件
2、lightning新建按钮,怎么重写在项目下新建时自动填充的父对象
点击对象管理器,新建对象项目(Test_Project),部门(Test_Department)
以下是部门(Test_Department)的字段表
标签 | API | 数据类型 | 值 |
部门名称 | Name | 文本(80) | |
项目 | Project_Dep__c | 查找(项目) | |
角色 | Role__c | 选项列表 |
项目经理 项目顾问 项目开发 项目测试 |
邮箱 | Email__c | 电子邮件 | |
报表权限 | Report_Access__c | 复选框 | |
描述 | Remarks__c | 文本区(255) |
先创建一个lightning组件Test_NewDepartment
<aura:component implements="lightning:actionOverride,
flexipage:availableForRecordHome,
force:hasRecordId,
flexipage:availableForAllPageTypes" access="global" description="Test_NewDepartment"> </aura:component>
组件继承的几个接口说明下
lightning:actionOverride:继承该接口才能覆盖标准按钮
force:hasRecordId:继承该接口才能通过“v.recordId"获取当前页面的记录ID
然后来处理第一个问题,lightning暂时不支持lookup字段的问题
经过了解,lightning提供了一个<lightning:recordEditForm>组件,通过<lightning:inputField>可以操作查找字段.
<aura:component implements="lightning:actionOverride,
flexipage:availableForRecordHome,
force:hasRecordId,
flexipage:availableForAllPageTypes" access="global" description="Test_NewDepartment">
<!-- 部门 --> <aura:attribute name="simpleDepartmentRecord" type="Test_Department__c" default="{‘SobjectType‘:‘Test_Department__c‘}"/> <!-- 错误消息-->
<aura:attribute name="recordError" type="String"/>
<!-- 标记按钮能否点击--> <aura:attribute name="flag" type="Boolean" default="true"/> <div aura:id="editDialog" role="dialog" tabindex="-1" aria-labelledby="header43" class="slds-modal slds-fade-in-open"> <div class="slds-modal__container"> <div class="slds-modal__header"> <h2 class="slds-text-heading--medium">{!(v.recordId == null?‘新增‘:‘更新‘) + ‘部门‘}</h2> </div> <lightning:messages /> <lightning:recordEditForm objectApiName="Test_Department__c"> <div class="slds-modal__content slds-p-around--medium slds-wrap" > <lightning:input aura:id="departmentId" label="用户名" name="userName" placeholder="请输入完整的用户名" required="true" value="{!v.simpleDepartmentRecord.Name}" /> <lightning:inputField class="customRequired" aura:id="roleId" fieldName="Role__c" value="{!v.simpleDepartmentRecord.Role__c}"/> <lightning:inputField class="customRequired" fieldName="Email__c" value="{!v.simpleDepartmentRecord.Email__c}"/> <lightning:inputField class="customRequired" aura:id="projectLookupId" fieldName="Project_Dep__c" value="{!v.simpleDepartmentRecord.Project_Dep__c}"/> <lightning:inputField class="customRequired" aura:id="reportId" fieldName="Report_Access__c" value="{!v.simpleDepartmentRecord.Report_Access__c}"/> <lightning:inputField fieldName="Remarks__c" value="{!v.simpleDepartmentRecord.Remarks__c}"/> </div> <div class="slds-modal__footer"> <lightning:button variant="neutral" label="Cancel" onclick="{!c.cancelDialog}" /> <lightning:button variant="brand" label="Submit" onclick="{!c.saveRecord}" disabled="{!v.flag}"/> </div> </lightning:recordEditForm> </div> </div>
<!-- 弹窗打开的时候,用一个遮罩层将页面变暗-->
<div aura:id="overlay" class="slds-backdrop slds-backdrop--open"></div> </aura:component>
此时预览下页面查看效果
通过<lightning:recordEditForm>组件,就能比较方便的重写新建/更新按钮,但此时会出现一个问题
当点击更新按钮的时候,会发现使用<lightning:input>的用户名没有办法进行更新,此时查阅相关文档
<Lightning:recordEditForm> 发现这样一句话:
The lightning:inputField component is used inside the lightning:recordEditForm to create editable fields.
The lightning:outputField component and other display components such as lightning:formattedName can be used to
display read-only information in your form.
简单说,除了使用<lightning:inputField>的字段是可编辑的,lightning:input,lightning:formattedName等其他标签都是只读的
于是这里就遇到一个很严重的问题,查阅文档知道lightning:inputField字段不支持onblur属性,它支持onchange属性,而需求是在输入用户名后通过接口实时对输入的数据进行校验并获取返回的用户ID.
直接操作看起来不太可行,于是想到了迂回解决的办法,把更新也当作新建处理.
在点击更新的时候,将页面记录ID传到后台进行初始化,把查询出来的部门信息反向填充到表单中,这样就能绕开<lightning:recordEditForm>更新时lightning:input无法编辑,而lightning:inputField又不支持onblur属性的问题.
PS:
此处补充一个<lightning:recordEditForm>组件的小问题,<lightning:recordEditForm>在提交按钮 <lightning:button variant="brand" label="Submit" onclick="{!c.saveRecord}" type="submit"/> 会有一个默认的提交行为,所以不小心就会出现提交两次的问题,此时在JSController提交方法中设置
// 取消默认的提交行为
event.preventDefault();
就能取消组件的默认提交行为,以下是文档的描述
To customize the behavior of your form when it loads or when data is submitted, use theonload
andonsubmit
attributes
to specify event handlers. If you capture the submit event and submit the form programmatically,
useevent.preventDefault()
to cancel the default behavior of the event. This prevents a duplicate form submission.
接下来处理第二个问题:在父对象项目的相关列表中创建部门对象时,如何自动填充父对象的问题.
很遗憾, Salesforce没有提供类似v.recordId这样的属性可以直接获取父级id,甚至在查阅解决方案的时候发现有人提了Idea
后来有个想法就是说不管怎么设计,相关列表创建子对象记录一定绕不开的就是通过url传递父对象的ID
所以在组件的Helper.js中写一个解析URL的方法
// 获取URL参数
getUrlParameter : function(component,event,name) {
name = name.replace(/[[]]/g, "\\$&");
var url = window.location.href;
var regex = new RegExp("[?&]" + name + "(=1.([^&#]*)|&|#|$)");
var results = regex.exec(url);
if (!results) return null;
if (!results[2]) return ‘‘;
return decodeURIComponent(results[2].replace(/+/g, " "));
}
在组件的Controller.js中打印父级ID
doInit : function(component, event, helper){
// 获取可能的父级id
var value = helper.getUrlParameter(component,event,‘inContextOfRef‘);
var context = JSON.parse(window.atob(value));
var parentId = context.attributes.recordId;
console.log(‘*** parentId:‘ + parentId);
},
判断如果parentId存在,则将Id传递到后台,查询父对象的信息并返回数据进行填充
// 从父级对象创建部门的时候给对应的字段预填充 @AuraEnabled public static String initFunction(String parentId){ System.debug(‘*** parentId:‘ + parentId); Test_Department__c permiss = new Test_Department__c(); // 考虑权部门以后除了项目还有其他的主表,这里要检验parentId属于那个对象 String prefix = Test_Project__c.sobjecttype.getDescribe().getKeyPrefix(); if (parentId.substring(0, 3) == prefix) { permiss.Project_Dep__c = parentId; } System.debug(‘*** 部门:‘ + permiss); return JSON.serialize(permiss); }
填充效果如下
以下附完整代码
1 Lightning组件代码 2 <aura:component implements="lightning:actionOverride,flexipage:availableForRecordHome,force:hasRecordId,flexipage:availableForAllPageTypes" 3 access="global" 4 description="Test_NewDepartment" 5 controller="Test_NewDepartmentCTl"> 6 <aura:attribute name="simpleDepartmentRecord" type="Test_Department__c" default="{‘SobjectType‘:‘Test_Department__c‘}"/> 7 <aura:attribute name="recordError" type="String"/> 8 9 <aura:handler name="init" value="{!this}" action="{!c.doInit}" /> 10 11 <div aura:id="editDialog" role="dialog" tabindex="-1" aria-labelledby="header43" class="slds-modal slds-fade-in-open"> 12 <div class="slds-modal__container"> 13 <div class="slds-modal__header"> 14 <h2 class="slds-text-heading--medium">{!(v.recordId == null?‘新增‘:‘更新‘) + ‘部门‘}</h2> 15 </div> 16 <lightning:messages /> 17 <lightning:recordEditForm objectApiName="Test_Department__c"> 18 <div class="slds-modal__content slds-p-around--medium slds-wrap" > 19 <lightning:input aura:id="permisssId" 20 label="用户名" 21 name="userName" 22 placeholder="请输入完整的用户名" 23 required="true" 24 onblur="{!c.checkPackageCode}" 25 value="{!v.simpleDepartmentRecord.Name}" /> 26 <lightning:inputField class="customRequired" 27 aura:id="roleId" 28 fieldName="Role__c" 29 value="{!v.simpleDepartmentRecord.Role__c}"/> 30 <lightning:inputField class="customRequired" 31 fieldName="Email__c" 32 value="{!v.simpleDepartmentRecord.Email__c}"/> 33 <lightning:inputField class="customRequired" 34 aura:id="projectLookupId" 35 fieldName="Project_Dep__c" 36 value="{!v.simpleDepartmentRecord.Project_Dep__c}"/> 37 <lightning:inputField class="customRequired" 38 aura:id="reportId" 39 fieldName="Report_Access__c" 40 onchange="{!c.changeReport}" 41 value="{!v.simpleDepartmentRecord.Report_Access__c}"/> 42 <lightning:inputField fieldName="Remarks__c" 43 value="{!v.simpleDepartmentRecord.Remarks__c}"/> 44 </div> 45 46 <div class="slds-modal__footer"> 47 <lightning:button variant="neutral" label="Cancel" onclick="{!c.cancelDialog}" /> 48 <lightning:button variant="brand" label="Submit" onclick="{!c.saveRecord}" /> 49 </div> 50 </lightning:recordEditForm> 51 </div> 52 </div> 53 <div aura:id="overlay" class="slds-backdrop slds-backdrop--open"></div> 54 </aura:component> 55 56 Lightning Controller代码 57 ({ 58 // 新建/更新初始化 59 // 1、直接点击新建按钮,不填充任何数据 60 // 2、相关列表创建部门,需要自动填充parentId信息 61 // 3、更新部门信息 62 doInit : function(component, event, helper){ 63 var recId = component.get("v.recordId"); 64 // 获取可能的父级id 65 var value = helper.getUrlParameter(component,event,‘inContextOfRef‘); 66 var context = JSON.parse(window.atob(value)); 67 var parentId = context.attributes.recordId; 68 console.log(‘*** parentId:‘ + parentId); 69 70 // 新建时,如果parentId 不为空,传递到后台get数据 71 // 更新时传递recId到后台,将数据组转后传回来 72 if ((!recId && parentId != undefined) || (recId != undefined || recId != null)) { 73 console.log(‘init‘); 74 helper.initHelper(component,recId,parentId); 75 } 76 }, 77 // 校验用户名数据 78 checkPackageCode:function(component, event, helper){ 79 // 校验package code 80 helper.validateuserName(component); 81 }, 82 //保存数据 83 saveRecord : function(component, event, helper) { 84 var Name = component.get(‘v.simpleDepartmentRecord.Name‘); 85 if (Name == null || Name == ‘‘) { 86 helper.showToast(‘提示‘,‘用户名不能为空‘,‘info‘); 87 return; 88 } 89 var Role = component.get(‘v.simpleDepartmentRecord.Role__c‘); 90 if (Role == null || Role == ‘‘) { 91 helper.showToast(‘提示‘,‘部门角色不能为空‘,‘info‘); 92 return; 93 } 94 var Email = component.get(‘v.simpleDepartmentRecord.Email__c‘); 95 if (Email == null || Email == ‘‘) { 96 helper.showToast(‘提示‘,‘用户邮箱不能为空‘,‘info‘); 97 return; 98 } 99 var Project = component.get(‘v.simpleDepartmentRecord.Project_Dep__c‘); 100 if (Project == null || Project == ‘‘) { 101 helper.showToast(‘提示‘,‘项目不能为空‘,‘info‘); 102 return; 103 } 104 // 取消默认的提交行为 105 event.preventDefault(); 106 helper.saveRecord(component); 107 }, 108 // 取消弹窗 109 cancelDialog: function(component, event, helper) { 110 var recId = component.get("v.recordId"); 111 if (!recId) { 112 var homeEvt = $A.get("e.force:navigateToObjectHome"); 113 homeEvt.setParams({ 114 "scope": "Test_Department__c" 115 }); 116 homeEvt.fire(); 117 } else { 118 helper.navigateTo(component, recId); 119 } 120 }, 121 // 复选框的值设定 122 changeReport:function(component, event, helper){ 123 var Report_Access = component.get(‘v.simpleDepartmentRecord.Report_Access__c‘); 124 component.set(‘v.simpleDepartmentRecord.Report_Access__c‘, !Report_Access); 125 }, 126 }) 127 128 Lightning Helper源码 129 ({ 130 // 父级Id不为空的情况下,将id传递到后台,校验数据,然后返回一个新的Test_Department__c进行组装 131 initHelper:function(component,recordId,parentId){ 132 var action = component.get("c.initFunction"); 133 action.setParams({ 134 "parentId": parentId, 135 "recordId":recordId 136 }); 137 action.setCallback(this, function(response){ 138 var state = response.getState(); 139 if (state === ‘SUCCESS‘) { 140 var result = response.getReturnValue(); 141 var dcObj = JSON.parse(result); 142 component.set(‘v.simpleDepartmentRecord‘, dcObj); 143 } 144 }); 145 $A.enqueueAction(action); 146 }, 147 // 校验数据 148 validateuserName : function(component) { 149 var username = component.get(‘v.simpleDepartmentRecord.Name‘); 150 console.log(‘username:‘ + username); 151 152 var action = component.get("c.validateName"); 153 action.setParams({ 154 "username": username, 155 }); 156 action.setCallback(this, function(response){ 157 var state = response.getState(); 158 if (state === "SUCCESS") { 159 var dcObj = JSON.parse(response.getReturnValue()); 160 if (dcObj.errorCode == ‘error‘) { 161 this.showToast(dcObj.errorTitle,dcObj.errorMsg,dcObj.errorStatu); 162 }else{ 163 // 将校验数据传递的值进行回写 164 } 165 }else{ 166 this.showToast(‘错误‘,‘出现未知错误,请联系管理员!‘,‘error‘); 167 console.log(‘error:‘ + response.getErrors()); 168 } 169 }); 170 $A.enqueueAction(action); 171 }, 172 // 保存数据 173 saveRecord:function(component){ 174 var action = component.get("c.saveSimpleRecord"); 175 action.setParams({ 176 "packageRecord": JSON.stringify(component.get("v.simpleDepartmentRecord")), 177 }); 178 action.setCallback(this, function(response){ 179 var state = response.getState(); 180 if (state === "SUCCESS") { 181 var dcObj = JSON.parse(response.getReturnValue()); 182 if (dcObj.errorCode == ‘error‘) { 183 this.showToast(dcObj.errorTitle,dcObj.errorMsg,dcObj.errorStatu); 184 }else{ 185 this.showToast(dcObj.errorTitle,dcObj.errorMsg,dcObj.errorStatu); 186 window.location.reload(); 187 window.location.href = "/"+ dcObj.dcpId; 188 } 189 }else{ 190 this.showToast(‘错误‘,‘出现未知错误,请联系管理员!‘,‘error‘); 191 console.log(‘error:‘ + response.getErrors()); 192 } 193 }); 194 $A.enqueueAction(action); 195 }, 196 navigateTo: function(component, recId) { 197 // 页面跳转到新记录 198 var navEvt = $A.get("e.force:navigateToSObject"); 199 navEvt.setParams({ 200 "recordId": recId 201 }); 202 navEvt.fire(); 203 }, 204 // type = ‘error‘, ‘warning‘, ‘success‘, or ‘info‘.default is ‘other‘ 205 showToast : function(title, message, type){ 206 var toastEvent = $A.get("e.force:showToast"); 207 toastEvent.setParams({ 208 "title": title, 209 "message": message, 210 "type" : type 211 }); 212 toastEvent.fire(); 213 }, 214 // 获取URL参数 215 getUrlParameter : function(component,event,name) { 216 name = name.replace(/[[]]/g, "\\$&"); 217 var url = window.location.href; 218 var regex = new RegExp("[?&]" + name + "(=1.([^&#]*)|&|#|$)"); 219 var results = regex.exec(url); 220 if (!results) return null; 221 if (!results[2]) return ‘‘; 222 return decodeURIComponent(results[2].replace(/+/g, " ")); 223 } 224 }) 225 226 最后的Apex类源码 227 /************************************************************************************************* 228 * Name: Test_NewDepartmentCtl 229 * Object: Test_Department__c 230 * Purpose: Override create/edit department, validate username by service callout 231 * Author: Ricardo Lu 232 * Create Date: 2019-01-19 233 * Modify History: 234 * 2019-01-19 Create this class 235 *************************************************************************************************/ 236 public with sharing class Test_NewDepartmentCTl { 237 // 从父级对象创建部门的时候给对应的字段预填充 238 @AuraEnabled 239 public static String initFunction(String parentId,String recordId){ 240 System.debug(‘*** parentId:‘ + parentId + ‘,recordId:‘ + recordId); 241 242 Test_Department__c department = new Test_Department__c(); 243 // 更新 244 if (recordId != null) { 245 department = [SELECT Name,Role__c,Email__c,Project_Dep__c,Report_Access__c,Remarks__c FROM
Test_Department__c WHERE Id =:recordId]; 246 }else if (parentId != null) { 247 // 考虑部门以后除了项目还有其他的主表,这里要检验parentId属于那个对象 248 String prefix = Test_Project__c.sobjecttype.getDescribe().getKeyPrefix(); 249 if (parentId.substring(0, 3) == prefix) { 250 department.Project_Dep__c = parentId; 251 } 252 } 253 System.debug(‘*** 部门:‘ + department); 254 return JSON.serialize(department); 255 } 256 257 @AuraEnabled 258 public static String validateName(String username){ 259 ReturnWrapper wrapper = new ReturnWrapper(); 260 if (username == null || username == ‘‘) { 261 wrapper.errorCode = ‘error‘; 262 wrapper.errorMsg = ‘请输入用户名‘; 263 wrapper.errorTitle = ‘提示‘; 264 wrapper.errorStatu = ‘warning‘; 265 return JSON.serialize(wrapper); 266 } 267 268 try { 269 // 对username进行需要的接口校验 270 } catch(Exception ex) { 271 System.debug(‘*** line:‘ + ex.getLineNumber()); 272 System.debug(‘*** messgae:‘ + ex.getMessage()); 273 wrapper.errorCode = ‘error‘; 274 wrapper.errorTitle = ‘错误‘; 275 wrapper.errorStatu = ‘error‘; 276 wrapper.errorMsg = ‘校验错误,请联系管理员!‘; 277 return JSON.serialize(wrapper); 278 } 279 wrapper.errorCode = ‘success‘; 280 wrapper.errorTitle = ‘成功‘; 281 wrapper.errorStatu = ‘success‘; 282 wrapper.errorMsg = ‘‘; 283 return JSON.serialize(wrapper); 284 } 285 @AuraEnabled 286 public static String saveSimpleRecord(String packageRecord){ 287 ReturnWrapper wrapper = new ReturnWrapper(); 288 289 Map<String, Object> objectField = new Map<String, Object>(); 290 try{ 291 292 objectField = (Map<String, Object>) JSON.deserializeUntyped(packageRecord); 293 294 // 部门Id 295 String packageId = null; 296 if(objectField.get(‘Id‘) != null){ 297 packageId = (String)objectField.get(‘Id‘); 298 } 299 300 // 部门用户名 301 String packageName = (String)objectField.get(‘Name‘); 302 303 // 用户名不能为空 304 if(packageName == null || packageName.trim().length() == 0){ 305 wrapper.errorCode = ‘error‘; 306 wrapper.errorMsg = ‘用户名称不能为空!‘; 307 wrapper.errorTitle = ‘提示‘; 308 wrapper.errorStatu = ‘warning‘; 309 return JSON.serialize(wrapper); 310 } 311 312 // 部门角色 313 String packageRole = (String)objectField.get(‘Role__c‘); 314 // Email__c 315 String packageEmail = String.valueOf(objectField.get(‘Email__c‘)); 316 // Project_Dep__c 317 Object packageProject = objectField.get(‘Project_Dep__c‘); 318 String projectId = String.valueOf(packageProject); 319 projectId = projectId.replace(‘(‘,‘‘).replace(‘)‘,‘‘); 320 321 // Report_Access__c:是否允许报表 322 Boolean packageReportAccess = false; 323 if (objectField.get(‘Report_Access__c‘) != null) { 324 packageReportAccess = (Boolean)objectField.get(‘Report_Access__c‘); 325 } 326 // Remarks__c 327 String packageRemarks = (String)objectField.get(‘Remarks__c‘); 328 329 // 新建 or update 部门 330 Test_Department__c dcp = new Test_Department__c(); 331 dcp.Id = packageId; 332 dcp.Name = packageName; 333 dcp.Role__c = packageRole; 334 dcp.Project_Dep__c = projectId; 335 dcp.Email__c = packageEmail; 336 dcp.Report_Access__c = packageReportAccess; 337 dcp.Remarks__c = packageRemarks; 338 upsert dcp; 339 340 wrapper.errorCode = ‘success‘; 341 wrapper.errorMsg = ‘恭喜,部门保存成功!‘; 342 wrapper.errorTitle = ‘成功‘; 343 wrapper.errorStatu = ‘success‘; 344 wrapper.dcpId = dcp.Id; 345 346 return JSON.serialize(wrapper); 347 } catch(Exception ex) { 348 System.debug(‘error:‘ + ex.getLineNumber()); 349 System.debug(‘error:‘ + ex.getMessage()); 350 wrapper.errorCode = ‘error‘; 351 wrapper.errorMsg = ‘保存错误,请联系管理员!‘; 352 wrapper.errorTitle = ‘错误‘; 353 wrapper.errorStatu = ‘error‘; 354 return JSON.serialize(wrapper); 355 } 356 } 357 358 public class ReturnWrapper{ 359 public String errorCode{get;set;} 360 public String errorTitle{get;set;} 361 public String errorStatu{get;set;} 362 public String errorMsg {get;set;} 363 public String dcpId{get;set;} 364 } 365 }
以上是关于Salesforce Lightning开发学习重写新建/更新按钮的主要内容,如果未能解决你的问题,请参考以下文章
salesforce零基础学习(九十五)lightning out
salesforce lightning零基础学习 Aura Js 浅谈一: Component篇
salesforce lightning零基础学习Lightning Data Service(LDS)
学习Salesforce | Platform Developer Ⅰ 平台初级开发认证考试指南及备考资源
salesforce lightning零基础学习(十三) 自定义Lookup组件(Single & Multiple)