Skip to content

New method for executing on save operations #77

@iGrubesic

Description

@iGrubesic

Current Approach

At the moment when using a field that needs to mutate the dataset on save for example the ImageComponent needing to execute a file upload and set the value to the uploaded URL, the component itself pushes its save method into a service. This method is then called when save is triggered. The save method edits the control's value to the exit value.

This approach has a number of problems:

  • The form builder component that created the field needs to be alive when save is triggered. This isn't always the case, the page builder creates multiple form builder instances.
  • We're editing the value of the control not the save object. This means value changes triggers multiple times during the save process.

current ImageComponent save method

save(moduleId: string, documentId: string) {
    if (this.value) {
      if (
        this.imageUrl.value &&
        this.imageUrl.value !== this.value.name
      ) {
        return of(this.imageUrl.value).pipe(
          tap(() => this.cData.control.setValue(this.imageUrl.value))
        );
      } else {
        const name = this.cData.preserveFileName ? this.value.name : [
          moduleId,
          documentId,
          random.string()
        ].join('-') +
          /**
           * TODO:
           * Maybe we should put a type extension based on type
           * instead of taking from the name
           */
          (this.value.name.split('.')[1]);

        return from(
          this.storage.upload(name, this.value, {
            contentType: this.value.type,
            customMetadata: {
              moduleId,
              documentId,
              ...(this.cData.generatedImages &&
                formatGeneratedImages(this.cData.generatedImages))
            }
          })
        ).pipe(
          switchMap((res: any) => res.ref.getDownloadURL()),
          tap(url => this.cData.control.setValue(url))
        );
      }
    } else {
      this.cData.control.setValue(this.imageUrl.value);
      return of({});
    }
  }

Desired Approach

  • All of the properties that need to be mutated during saving need to be accumulated when the form is created along with data pointers.
  • Each such component needs to provide a self-sufficient method (meaning it doesn't depend on anything in the angular component) separate from the component itself.
  • This method receives as arguments the initial value, current value, configuration from the definitions, moduleId, documentId and should return the final value.
  • When save is triggered all of these methods are called in parallel.
  • Once they all complete successfully the final object is mutated using the pointers collected initially.
  • These methods aren't even called if the initial and current value don't differ

example save method

export function ImageSave(
  initial: string,
  current: any,
  configuration: any,
  moduleId: string,
  documentId: string
) {
  return from(
    this.storage.upload(current.name, current.value, {
      contentType: current.type,
      customMetadata: {
        moduleId,
        documentId,
        ...(configuration.generatedImages &&
          formatGeneratedImages(configuration.generatedImages))
      }
    })
  ).pipe(
    switchMap((res: any) => res.ref.getDownloadURL())
  );
}

Note: We still need to properly define this.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions