How do I retrieve a newly created Item object when created on a synthetic Actor?

Author: zeel
Message:

Awe man… this is going to be a problem.

I want the editor for newly created items to appear automatically when the item is created.

This seems like a simple enough thing, I already have logic for opening the items, I just need to wait for an item to be created, and trigger that logic with the id of the new item.

async addFeature(event) {
    let type = event.currentTarget.dataset.type == "spell" ? "spell" : "item";
    let item = await this._onItemCreate(event);
    let id = item._id;
    if (type == "item") this.openItemEditor(event, id);
    else this.openSpellEditor(event, id);
}

Unfortunately, _onItemCreate (from the parent class) doesn’t return the expected value. Confusing, because taking a look it seems like it should:

return this.actor.createOwnedItem(itemData);

Surely creatOwnedItem() returns a promise that fulfills to the item data?

It does! Except not in this case. Up the chain of calls, and we find that ActorTokenHelper.createEmbededEntity() is used as an indirection instead of Entity.createEmbeddedEntity() directly.

But that method doesn’t return the newly created entity, it returns the results of Token.update() when it adds the entity to the token (synthetic actor). And those results are… a reference to the Token object, not the Item object.

Can anyone see a way to get the id of the new Item?

The only option I’m seeing is storing an Array of item IDs before the add, and then finding the Item that wasn’t in my Array afterward. But that seems like a crappy way to do something that should be straightforward.

Author: Daddi

Message:

<@!398134675002097666> I had the same problem. I don’t have an answer for your question, I did it like this, which simply ignores synthetic actors :S

    /**
     * Helper function to create a new item.
     * Render parameter determines if the items sheet should be rendered.
     */
    static async createNewItem(itemData, sheet, render = true) {
        // Create item and render sheet afterwards
        const newItem = await sheet.actor.createOwnedItem(itemData);

        // Tokens don't return the new item
        if (!render || sheet.actor.isToken) return;

        // We have to reload the item for it to have a sheet
        const createdItem = sheet.actor.getOwnedItem(newItem._id);
        createdItem.sheet.render(true);
    }

I hope the API will get better in regards to synthetic actors in the future.
Your idea from before (using a diff of the items before) should work. But yeah, thats not a great solution :confused:

Author: zeel

Message:

Alright, well I did it the way I didn’t want to do it. <@!186430240493404171>, you might be interested in this:

async addFeature(event) {
    let type = event.currentTarget.dataset.type == "spell" ? "spell" : "item";
    let items = [...this.actor.items].map(i => i.id);
    await this._onItemCreate(event);
    let item = [...this.actor.items].find(i => !items.includes(i.id));

    let id = item.id;
    if (type == "item") this.openItemEditor(event, id);
    else this.openSpellEditor(event, id);
}

The reason for the spell/item differentiation is just an implementation quirk of my module and can be ignored.
I think technically the map keys are the item ids? So I might be doing something superfluous, but I didn’t want to rely on that.

This should be resolved in 0.7.2

It should be possible to get the item back without issue.