Custom property editor - get parent guid

Hey there!

I’m using v16.4.1 and I was building a custom property editor to get a property’s value from the parent and display it as a Umb radio button list.

In the old backoffice (with angular) we had the context of the node with the parent Id in it and we even had services to get the content from the node we wanted.

I think I’m right to assume that the “content from the node” part is to be made using the umbraco management API (which I’m sort-of using: I built my custom management api endpoint that expects a guid and gets the property I want from it, whether it is published or just saved).

The step I’m having trouble with is the “get parent Id”. I’ve came across this post which led me to this post and I couldn’t make this work for the life of me. I tried the UMB_DOCUMENT_WORKSPACE_CONTEXT, changed to UMB_PARENT_ENTITY_CONTEXT (as parentUnique was mark deprecated through the first context) and what I had was either undefined parent id OR grand-parent id instead.

I’ll share my code here, I must be doing something completely wrong so feel free to say anything and everything you see wrong :slight_smile:

import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import { UMB_PARENT_ENTITY_CONTEXT } from '@umbraco-cms/backoffice/entity';
import type { UmbParentEntityContext } from '@umbraco-cms/backoffice/entity';
import DataService from './dataService';
import type { UmbRadioButtonItem } from '@umbraco-cms/backoffice/components';

@customElement('my-custom-element')
export class MyCustomElement extends UmbLitElement {
  #parentEntityContext: UmbParentEntityContext | null = null;

  @property({ type: String })
  public value = '';

  @property({ type: Array })
  list: UmbRadioButtonItem[] = [];

  async #loadProfiles() {
    let parentId = this.#parentEntityContext?.getParent()?.unique;
    if (!parentId) return;
    this.list = await this._dataService.fetchProfiles(parentId, 'pt-PT');
  }

  private _dataService: DataService = new DataService();

  constructor() {
    super();
    this.consumeContext(UMB_PARENT_ENTITY_CONTEXT, (context) => {
      if (context) {
        this.#parentEntityContext = context;
        this.#loadProfiles();
      } else {
        this.#parentEntityContext = null;
      }
    });
  }

  override render() {
    return html`
    <umb-input-radio-button-list
      .list=${this.list}
      .value=${this.value}>
    </umb-input-radio-button-list>
  `;
  }
}

export default MyCustomElement;

declare global {
  interface HTMLElementTagNameMap {
    'my-custom-element': MyCustomElement;
  }
}

note 1: my knowledge with web components and Lit is scarce. I’m trying to learn as I go but I’m having some trouble keeping up…
note 2: my async #loadprofiles() function only exists because I cannot use await in constructor (I might change it to a callback inside the callback);
note 3: my DataService is a class that has the fetch method to get the “profiles” list I want

Thank you for you time :slight_smile:

It could be that at the time you recieve the context it has not yet loaded the parent.
So I would suggest this instead:

this.consumeContext(UMB_PARENT_ENTITY_CONTEXT, (context) => {
      this.observe(context?.parent, (parent) => {
        if (parent?.unique) {
          this.list = await this._dataService.fetchProfiles(parent?.unique, 'pt-PT');
        }
      }
    });

In this way your observing the value of the parent, meaning you will get the value when its there.
And if it changes then you will also get updated. Like if the item was moved while your on it. — not a very likely case, but then your safe.

I hope that works out for you.

Ps. we encourage everyone to be as reactive as possible, cause one day we will implement live-updates and then things will change without it being the viewers actions that initiated it. So always assume a change could happen. :wink: