Field Plugin with multiple values and trigger custom hook

I am still new to plugins/field-plugins and i am going to build a field, where i can edit multiple values, but if i get the concept of field-plugins right, only one value can be stored. unfortunately i can’t find any easy examples with multiple values… so i tried the following and would like to know if that would be a common solution.

in the blueprint.yml i add my new field

multitest:
  type: multitest

This should result in one json string in the txt-file i guess

Multitest: {"prop1":"testA","prop2":"testB"}

So in the field’s vue-file i would go to parse that JSON to an object.
To save i would stringify and emit that object.

<template>
    <div>
        <input type="text" ref="prop1" :value="values.prop1" @input="onInput">
        <input type="text" ref="prop2" :value="values.prop2" @input="onInput">
    </div>
</template>

<script>
export default {
    props: {
        value: String
    },
    data() {
        return {
            values: this.value ? JSON.parse(this.value) : { "prop1": "", "prop2": "" }
        };
    },
    methods: {
        onInput(event) {
            this.values.prop1 = this.$refs.prop1.value;
            this.values.prop2 = this.$refs.prop2.value;
            this.$emit("input", JSON.stringify(this.values));
        }
    }
}
</script>

That works so far.
I had some issues, when the value was empty.
So i added that condition and add an empty object, with the correct but empty structure, when value is empty.

What i am not sure about, is the timing to parse the value. is data() correct?
I guess there is no created() / this.load in field-plugins (like in section-plugins)?

If i need some other value from the page by API, when should i do that?
Also in data() or in created()? What is the differnet in that lifecycle regarding to field-plugins?

That depends, there are different lifecycle stages (created, mounted, etc), and also methods, computed, watch. If you need to react on changes, for example, you would need watch method, like e.g. Creating a custom block type from scratch | Kirby CMS

Good Example. I will have a Look! Thx @texnixe

to get contents of the page, i used the following API call in the created-lifecycle.
works good. because of your hint, i am going to checkout the watch-method as well.

created() {
        this.$api.get(this.$view.path, { select: 'content' })
            .then(response => {
                console.log('success', response)
            })
            .catch(error => {
                console.log('error', error)
            });
    },

i have another question regarding custom hooks.
How can we call a custom hook from vue?

and what would be best, to send the page as payload?
/api/pages/:id | Kirby CMS without the select param?

'hooks' => [
        'test.test123' => function ($page) {
            if ($page->isChildOf('messages')) {
                //do whatever you want...
            }
        },
    ]

Thx!

A Kirby hook is something that runs server side, so to trigger it, you need an AJAX call.

What do you need the hook for?

to call the same method from multiple plugins with the page as payload, which will push a notification to an app by firebase and also log that server side by site()->logger("test.log")->log("xyz")
so i thought i can trigger a custom hook from each plugin…, but if i can’t call them directly by javascript, is there any advantage to a route?

beside the interactive method to push a page on a buttonclick, there should also be an option to push a page by autopush with a cronjob - similar to autopublish … i am not sure, if a cron-job can use that hook?

<?php

Kirby::plugin('xyz/pusher', [
    'sections' => [
        'pushtest_section' => require __DIR__ . '/sections/pushtest.php',
    ],
    'fields' => [
        'pushtest_field' => require __DIR__ . '/fields/pushtest.php',
    ],
    'hooks' => [
        'xyz.push' => function ($page) {
            site()->logger("push.log")->log("New Message is pushed: " . $page->title());
           // -> firebase action based on $page->intendedTemplate();
        },
    ]
]);

No, I don’t think so, the route can do the job.

it does. i changed the hook to a route and call them via fetch from several plugins.

Kirby::plugin('xyz/pusher', [

    ...
    
    'routes' => function ($kirby) {
        return [
            [
                'pattern' => 'pushPage/(:any)',
                'action' => function (string $slug) {
                    $now =  Date::now();

                    // -> do the firebase stuff

                    site()->logger("push.log")->log("New Message " . $slug . ' - ' .  $now);
                    return [
                        'status' => 'ok',
                        'code' => '200',
                        'date' => $now
                    ];
                }
            ]
        ];
    }
export default {
    props: {
        value: String
    },
    data() {
        return {
            slug:'',
            values: this.value ? JSON.parse(this.value) : { 'prop1': '', 'prop2': null }
        };
    },
    created() {
        this.$api.get(this.$view.path)
            .then(response => {
                this.slug = response.slug;
            })
            .catch(error => {
                console.log('error', error)
            });
    },
    methods: {
        async push() {
            const response = await fetch("/pushPage/"+this.slug);
            const data = await response.json();
            this.pushes.push(data.date)
        },
        onInput(event) {
            this.values.prop1 = this.$refs.prop1.value;
            this.values.prop2 = this.$refs.prop2.value;
            this.$emit("input", JSON.stringify(this.values));
        }
    }
}

Thx @texnixe for always pointing into the right direction!