Función de devolución de llamada de paso LWC dinámicamente
Tengo un componente modal en el que paso métodos de controlador de dos botones que son devoluciones de llamada.
Estos dos botones están conectados a un captador con la intención de que pueda anularlos, lo que me cuesta hacer.
Ejemplo de código:
export default class CreateCaseApp extends LightningElement {
// Default button handlers
_saveHandler = {
cb: this._modalSaveHandler,
label: "Create Case",
variant: "brand",
};
_cancelHandler = {
cb: this._modalCancelHandler,
label: "Cancel",
variant: "netrual",
class: "btn-left",
};
/**
* Getter: Save handler callback and button props
*/
get saveHandler() {
return this._saveHandler;
}
/**
* Getter: Cancel handler callback and button props
*/
get cancelHandler() {
return this._cancelHandler;
}
/**
* Save event send to modal
* @param {*} event
*/
_modalSaveHandler = (event) => {
console.log("Save Clicked");
};
/**
* Handler event sent to modal
* @param {*} event
*/
_modalCancelHandler = (event) => {
console.log("Cancel Clicked");
};
// Questionable code below
/**
* Handler event sent to modal for override
* @param {*} event
*/
_modalOverrideHandler = (event) => {
console.log("Override Clicked");
};
onDispatchedEventFromChild(event) {
if (event.detail == "nodata") {
// Override save handler button
this._saveHandler = {
cb: this._modalOverrideHandler,
label: "Okay",
variant: "brand"
};
}
}
}
En el código anterior, los métodos de flecha inicial saveHandler()y cancelHandler()están pasando correctamente a través de la cbpropiedad en el objeto. Puedo hacer clic en estos botones en el componente secundario y ejecutan el método de este padre.
En la sección inferior del código, tengo un detector de eventos onDispatchedEventFromChild()que recibe datos de un componente secundario. Cuando se cumple la lógica de este método, estoy tratando de anular el _saveHandlerbotón configurándolo con this._saveHandler={...}.
Esto actualiza los detalles del botón, como la etiqueta y la variante, pero cuando hago clic en él, la nueva devolución de llamada referenciada no se activa.
¿Es posible hacer esto o lo estoy abordando incorrectamente? Intenté usar @tracken las dos variables, pero eso tampoco funcionó.
Editar:
HTML del componente principal
<template>
<c-modal
modal-header={modalHeader}
modal-save-handler={saveHandler}
>
<div
slot="modalContent"
class="modalContent slds-modal__content slds-p-around_medium"
>
<!-- Wrapper -->
<c-create-case-wrapper
contact-id={recordId}
onmodalheaderupdate={handleModalHeaderEvent}
onmodalhandlerupdate={handleModalHandlerEvent}
></c-create-case-wrapper>
<!-- Wrapper -->
</div>
</c-modal>
<!-- Main Modal Launch Button -->
<lightning-button
variant="brand"
label="Create Enterprise Case"
title="Create Enterprise Case"
onclick={handleClick}
class="slds-m-left_x-small"
></lightning-button>
<!-- Main Modal Launch Button -->
</template>
El padre está proporcionando la devolución de llamada para el clic del botón dentro del componente modal. Cuando se hace clic en un botón, el padre ejecuta ese método (en el padre).
En este ejemplo, <c-create-case-wrapper>también está cargando componentes secundarios basados en la lógica. Cuando se cumple cierta lógica dentro de esos componentes, necesito cambiar la devolución de llamada y la etiqueta del botón. Aquí es donde un niño enviaría un evento al padre para que sepa que necesito actualizar el botón modal.
Supuse que, dado que el botón se pasaba al modal de forma reactiva a través del captador, podía actualizar ese objeto / devolución de llamada para anular sus valores predeterminados. Esto funciona bien para las propiedades de la etiqueta y la variante, está pasando otra devolución de llamada / diferente que no funciona.
Respuestas
Hay algunas formas de cumplir con sus requisitos, como se menciona a continuación. Tenga en cuenta que los fragmentos de código se basan en el repositorio de github que señaló y, por lo tanto, tendrá que modificarlo un poco si es necesario. Además, solo he proporcionado los fragmentos de código que se agregarán o actualizarán (el resto de su código permanecerá como está).
Opción 1:
En el componente principal, introduzca un campo booleano privado overrideSavey un método _modalSaveDefaultHandler. Actualice el _modalSaveHandlercódigo para ejecutar en función del valor de la bandera booleana. Actualice el onDispatchedEventFromChildcódigo para alternar la bandera booleana según sus condiciones específicas cumplidas. Ahora, el componente modal secundario obtendrá la referencia de devolución de llamada a ambos _modalSaveDefaultHandlery a _modalOverrideHandlertravés _modalSaveHandler.
overrideSave = false;
_modalSaveHandler = (event) => {
if(!this.overrideSave){
this._modalSaveDefaultHandler(event);
}
else{
this._modalOverrideHandler(event);
}
};
_modalSaveDefaultHandler = (event) => {
console.log("Save Clicked");
};
onDispatchedEventFromChild() {
if (event.detail == "nodata") {
this.overrideSave = true;
}
}
Opcion 2:
En el HTML del componente modal, probablemente tenga el evento de clic conectado de esta manera <button class="slds-button slds-button_brand save" onclick={modalSaveHandler.cb}>. Reemplace esto con <button data-id="modalSaveBtn" class="slds-button slds-button_brand save">. Tenga en cuenta que hemos eliminado el cableado de eventos declarativos y lo haremos mediante programación. Además, hemos incluido un data-atributo para poder consultar el elemento de botón específico a través del código.
En el componente modal JS, introduzca un nuevo campo privado handleRefque se utilizará para contener la referencia a la devolución de llamada. Modifique el renderedCallbackmétodo para pasar la referencia de devolución de llamada (de modalSaveHandlerla propiedad pública) handleRefy agregue mediante programación el controlador de eventos de clic en el botón específico. Agregue un nuevo método público updateRegisteredEventque será llamado por el componente principal y este método será responsable de eliminar el antiguo detector de eventos, así como de agregar un nuevo detector de eventos.
handlerRef;
isFirstRender = true;
renderedCallback() {
if (this.isFirstRender) {
this.handlerRef = this.modalSaveHandler.cb;
this.template.querySelector('[data-id="modalSaveBtn"]').addEventListener('click', this.handlerRef);
this.isFirstRender = false;
}
}
@api updateRegisteredEvent(overrideFn) {
this.template.querySelector('[data-id="modalSaveBtn"]').removeEventListener('click', this.handlerRef);
this.template.querySelector('[data-id="modalSaveBtn"]').addEventListener('click', overrideFn);
}
En el JS del componente principal, actualice el onDispatchedEventFromChildcódigo para llamar al método público del componente secundario (pasando el método de anulación como parámetro de entrada).
onDispatchedEventFromChild() {
if (event.detail == "nodata") {
// Override save handler button
this._saveHandler = {
label: "Okay",
variant: "brand"
};
this.template.querySelector('c-modal').updateRegisteredEvent(this._modalOverrideHandler);
}
}
Opcion 3:
En el componente modal JS, defina los métodos del controlador de eventos y conéctelos en el onclickatributo HTML de forma declarativa. El código del controlador de eventos solo debe pasar los detalles del componente modal (o los detalles del formulario) al componente principal a través de un evento personalizado. Por lo tanto, no sabe cómo procesará los datos el componente principal.
En el componente principal, conecte los controladores de eventos correspondientes a los eventos personalizados (enviados por componente modal) e implemente su lógica personalizada en estos controladores de eventos según sus requisitos (y las condiciones específicas que deben cumplirse).
No proporcionamos ninguna muestra de código aquí porque esta es la forma directa de comunicación de eventos de LWC y, por lo tanto, debería ser más fácil de hacer. Sugeriría adoptar este enfoque ya que está en línea con el estándar LWC, define la función / responsabilidad específica de cada componente y se puede desarrollar como componentes reutilizables.
Información adicional: en su código actual, la función de devolución de llamada se pasa a través de lasaveHandlerpropiedad durante la inicialización del componente y ambos componentes pasan por los enlaces del ciclo de vida de la devolución de llamada conectada y renderizada. Por lo tanto, el ciclo de vida de inicio y procesamiento de LWC conecta la devolución de llamada al evento de clic del elemento de botón. Sin embargo, cuando laonDispatchedEventFromChildejecución actualiza la devolución de llamada mediante el objeto literal (this._savehandler), solo elrenderedCallbackganchodelciclo de vida se ejecuta en ambos componentes. Básicamente, esto reevalúa los elementos de la interfaz de usuario y los vuelve a reproducir, pero no hace nada sobre el cableado fn de devolución de llamada al evento de clic del botón. Esto podría deberse a la forma en que el registro de eventos de LWC funciona internamente.