Error in $doc.update()?

I'm not quite sure if I'm doing it wrong. The error I'm getting is:
foundry.js:13637 Uncaught (in promise) Error: You must provide an _id for every object in the update data Array.
at #preUpdateDocumentArray (foundry.js:13637:32)
at ClientDatabaseBackend._updateDocuments (foundry.js:13449:73)
at ClientDatabaseBackend.update (commons.js:8677:19)
at async Actor5e.updateDocuments (commons.js:8001:23)
at async Actor5e.update (commons.js:8098:23)
foundry.js:13637 Uncaught (in promise) Error: You must provide an _id for every object in the update data Array.
at #preUpdateDocumentArray (foundry.js:13637:32)
at ClientDatabaseBackend._updateDocuments (foundry.js:13449:73)
at ClientDatabaseBackend.update (commons.js:8677:19)
at async Actor5e.updateDocuments (commons.js:8001:23)
at async Actor5e.update (commons.js:8098:23)
Here's the component
<script>
import { log, update } from "~/src/helpers/Utility";
import { Timing } from "@typhonjs-fvtt/runtime/util";
import { createEventDispatcher, getContext, onDestroy, onMount } from "svelte";

export let document = false;

const dispatch = createEventDispatcher();
const doc = document || getContext("#doc");
const updateDebounce = (path) => Timing.debounce($doc.update({[path]: event.target.value }), 300);

$: systemAbilities = game.system.config.abilities
$: systemAbilitiesArray = Object.entries(systemAbilities);

</script>

<template lang="pug">
.attribute-entry.mt-sm
+each("systemAbilitiesArray as ability, index")
.flexrow.mb-sm
.flex1 {ability[1].label}
.flex3.right
input(type="number" value="{$doc.system.abilities[ability[1].abbreviation].value}" on:input="{updateDebounce(`system.abilities.${ability[1].abbreviation}.value`)}" style="width: 40px")

</template>
<script>
import { log, update } from "~/src/helpers/Utility";
import { Timing } from "@typhonjs-fvtt/runtime/util";
import { createEventDispatcher, getContext, onDestroy, onMount } from "svelte";

export let document = false;

const dispatch = createEventDispatcher();
const doc = document || getContext("#doc");
const updateDebounce = (path) => Timing.debounce($doc.update({[path]: event.target.value }), 300);

$: systemAbilities = game.system.config.abilities
$: systemAbilitiesArray = Object.entries(systemAbilities);

</script>

<template lang="pug">
.attribute-entry.mt-sm
+each("systemAbilitiesArray as ability, index")
.flexrow.mb-sm
.flex1 {ability[1].label}
.flex3.right
input(type="number" value="{$doc.system.abilities[ability[1].abbreviation].value}" on:input="{updateDebounce(`system.abilities.${ability[1].abbreviation}.value`)}" style="width: 40px")

</template>
Normally (e.g. in my system, as opposed to this module) $doc.update() just works for me. I haven't seen this _id error before. It seems weird because update is being called on $doc, which is a TJSDocument instance of the actor, so it has the _id already I would expect.
4 Replies
geoidesic
geoidesic5mo ago
Ahh.. nvm. The actor is in memory, so I need to use updateSource() not update()
TyphonJS (Michael)
You are also using Timing.debounce incorrectly. It should be:
const updateDebounce = Timing.debounce((path) => $doc.update({[path]: event.target.value }), 300);
const updateDebounce = Timing.debounce((path) => $doc.update({[path]: event.target.value }), 300);
Timing.debounce is a higher order function that returns a function with the specified debounce functionality around the callback / function specified as the first argument.
geoidesic
geoidesic5mo ago
I ended up with this:
<script>
import { log, update } from "~/src/helpers/Utility";
import { Timing } from "@typhonjs-fvtt/runtime/util";
import { createEventDispatcher, getContext, onDestroy, onMount } from "svelte";

export let document = false;

const dispatch = createEventDispatcher();
const doc = document || getContext("#doc");
const updateDebounce = Timing.debounce(updateValue, 300);

function updateValue(attr, event) {
const options = {system: {abilities: { [attr]: {value: Number(event.target.value)}}}};
$doc.updateSource(options)
$doc = $doc //<--- necessary for reactivity in last line of template
}

$: systemAbilities = game.system.config.abilities
$: systemAbilitiesArray = Object.entries(systemAbilities);

</script>

<template lang="pug">
.attribute-entry.mt-sm
.flexrow.mb-sm
.flex3.left Ability
.flex1.center Score
.flex1.center Modifier
+each("systemAbilitiesArray as ability, index")
.flexrow.mb-sm
.flex3.left {ability[1].label}
.flex1.center
input.center(type="number" value="{$doc.system.abilities[ability[1].abbreviation].value}" on:input!="{updateDebounce(ability[1].abbreviation, event)}")
.flex1.center.align-text-with-input {$doc.system.abilities[ability[1].abbreviation].mod}
</template>
<script>
import { log, update } from "~/src/helpers/Utility";
import { Timing } from "@typhonjs-fvtt/runtime/util";
import { createEventDispatcher, getContext, onDestroy, onMount } from "svelte";

export let document = false;

const dispatch = createEventDispatcher();
const doc = document || getContext("#doc");
const updateDebounce = Timing.debounce(updateValue, 300);

function updateValue(attr, event) {
const options = {system: {abilities: { [attr]: {value: Number(event.target.value)}}}};
$doc.updateSource(options)
$doc = $doc //<--- necessary for reactivity in last line of template
}

$: systemAbilities = game.system.config.abilities
$: systemAbilitiesArray = Object.entries(systemAbilities);

</script>

<template lang="pug">
.attribute-entry.mt-sm
.flexrow.mb-sm
.flex3.left Ability
.flex1.center Score
.flex1.center Modifier
+each("systemAbilitiesArray as ability, index")
.flexrow.mb-sm
.flex3.left {ability[1].label}
.flex1.center
input.center(type="number" value="{$doc.system.abilities[ability[1].abbreviation].value}" on:input!="{updateDebounce(ability[1].abbreviation, event)}")
.flex1.center.align-text-with-input {$doc.system.abilities[ability[1].abbreviation].mod}
</template>
The $doc = $doc – is needed to make the mod value (last line of the template) reactive (from https://learn.svelte.dev/tutorial/updating-arrays-and-objects) It feels inelegant. Is there a better way to facilitate nested reactivity when using $doc.update() or $doc.updateSource()?
TyphonJS (Michael)
Presently, no because $doc.updateSource doesn't trigger the DB update response / callbacks. However, I'll look into adding an updateSource method directly to TJSDocument which will invoke the underlying updateSource of any wrapped core document, but will also trigger reactivity for in memory changes. In this case you'll drop the $ and it will just be doc.updateSource(...). I might also add a correponding update method to TJSDocument. So, in 0.2.0 there should be a way to automatically trigger reactivity w/ TJSDocument for in memory usage.
Want results from more Discord servers?
Add your server