Home > Mobile >  Laravel Inertiajs: How to render a generated Vue String To Html on Server side or frontend
Laravel Inertiajs: How to render a generated Vue String To Html on Server side or frontend

Time:04-11

I have implemented a contact formula where the siteadmin can edit the whole formula from his admin panel in with basic laravel and blade templates.

Now I would like to implement the same in inertiajs (vuejs).

I have made a tool that creates the necassery vue code. So now I would like to render this code on the server side or dynamically render it when the site is loaded.

I'm still not very familiar with vue but I have seen some libraries like vue3-runtime-template but they did not work.

The code I want to render looks like this:

<Field
    classes="transition duration-500 ease-in-out opacity-100 text-center required">
        <label>
            Was ist das Thema Ihres Anliegens?
        </label>
        <div >
            <div >
                <Input type="radio" id="offer" name="category"
                    :value="'offer'"
                    classes="opacity-0 absolute left-1/2 peer"
                    v-model="form.category"
                />
                <Label for="offer"
                    classes="px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full"
                >
                    Fragen zum Angebot
                </Label>
            </div>
        <div >
            <Input type="radio" id="business" name="category"
                :value="'business'"
                classes="opacity-0 absolute left-1/2 peer"
                v-model="form.category"
            />
            <Label for="business"
                classes="px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full"
            >
                Geschäftliche Anfrage
            </Label>
        </div>
        <div >
            <Input type="radio" id="technical" name="category"
                :value="'technical'"
                classes="opacity-0 absolute left-1/2 peer"
                v-model="form.category"
            />
            <Label for="technical"
                classes="px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full"
            >
                Technische Probleme
            </Label>
        </div>
        <div >
             <Input type="radio" id="other" name="category"
                 :value="'other'"
                 classes="opacity-0 absolute left-1/2 peer"
                 v-model="form.category"
             />
             <Label for="other"
                 classes="px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full"
             >
                 Sonstiges
             </Label>
        </div>
    </div>
</Field>

What I have already tried:

v-runtime-template, vue3-runtime-template, v-html and this. The probelem with the following approach is that I cannot render the htmlBefore and htmlAfter separately .

<Field v-for="(children, index) in fields" :key="index"
       classes="transition duration-500 ease-in-out text-center"
       :
>
    <component :is="child.componentType" v-for="(child) in children" v-bind="child" />
</Field>
data() {
    return {
        fields: [
            [
                {
                    htmlBefore: '<label for="category">'  
                        '             Was ist das Thema Ihres Anliegens?'  
                        '        </label>'  
                        '        <div >'  
                        '             <div >',
                    componentType: "Input",
                    type: "radio",
                    id: "offer",
                    name: "category",
                    value: "offer",
                    classes: "opacity-0 absolute left-1/2 peer",
                    model: this.form.category,
                },
                {
                    componentType: "Label",
                    forInput: "offer",
                    classes: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
                    labelText: "Fragen zum Angebot",
                    htmlAfter: "</div>",
                },
                {
                    htmlBefore: '<div >',
                    componentType: "Input",
                    type: 'radio',
                    id: 'business',
                    name: 'category',
                    value: "business",
                    classes: "opacity-0 absolute left-1/2 peer",
                    model: this.form.category,
                },
                {
                    componentType: "Label",
                    forInput: "business",
                    classes: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
                    labelText: "Geschäftliche Anfrage",
                    htmlAfter: "</div>",
                },
                {
                    htmlBefore: '<div >',
                    componentType: "Input",
                    type: 'radio',
                    id: 'technical',
                    name: 'category',
                    value: "technical",
                    classes: "opacity-0 absolute left-1/2 peer",
                    model: this.form.category,
                },
                {
                    componentType: "Label",
                    forInput: "technical",
                    classes: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
                    labelText: "Technische Probleme",
                    htmlAfter: "</div>",
                },
                {
                    htmlBefore: '<div >',
                    componentType: "Input",
                    type: 'radio',
                    id: 'other',
                    name: 'category',
                    value: "other",
                    classes: "opacity-0 absolute left-1/2 peer",
                    model: this.form.category,
                },
                {
                    componentType: "Label",
                    forInput: "other",
                    classes: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
                    labelText: "Sonstiges",
                    htmlAfter: "</div> </div>",
                },
            ],
            [
                {
                    componentType: "Textarea",
                    classes: "w-full h-80 resize-none !text-wonder-blue mt-2 rounded-2xl placeholder-shown:border-wonder-blue",
                    name: "message",
                    minLength: 5,
                    maxLength: 5000,
                    placeholder: "Hier haben Sie genug Platz, um mir Ihr Anliegen zu schildern",
                    model: this.form.message,
                },
            ],
            [
                {
                    htmlBefore: '<div >'  
                        '                        <div >',
                    componentType: "Input",
                    name: "firstname",
                    placeholder: "Vorname*",
                    classes: "mt-4",
                    model: this.form.firstname
                },
                {
                    componentType: "Input",
                    name: "lastname",
                    placeholder: "Nachname*",
                    classes: "mt-4",
                    model: this.form.lastname,
                    htmlAfter: "</div>",
                },
                {
                    componentType: "Input",
                    isRequired: false,
                    name: "company",
                    placeholder: "Unternehmen",
                    model: this.form.company,
                },
                {
                    componentType: "Input",
                    isRequired: false,
                    name: "website",
                    placeholder: "Website",
                    model: this.form.website,
                },
                {
                    componentType: "Input",
                    isRequired: false,
                    name: "phone",
                    placeholder: "Telefonnummer",
                    model: this.form.phone,
                },
                {
                    componentType: "Input",
                    type: "email",
                    name: "email",
                    placeholder: "E-Mail Adresse*",
                    model: this.form.email,
                },
                {
                    htmlBefore: '<div >',
                    componentType: "Input",
                    type: "hidden",
                    name: "subscribe_newsletter",
                    model: this.form.subscribe_newsletter,
                    classes: "hidden",
                    value: 0,
                },
                {
                    htmlBefore: '<div >',
                    componentType: "Input",
                    type: "checkbox",
                    name: "subscribe_newsletter",
                    model: this.form.subscribe_newsletter,
                    classes: "form-checkbox !px-2 !hover:ring-none",
                    value: 1,
                    isRequired: false,
                },
                {
                    componentType: "Label",
                    forInput: "subscribe_newsletter",
                    labelText: "Newsletter abonnieren",
                    htmlAfter: "</div>",
                },
                {
                    htmlBefore: '<div >',
                    componentType: "Input",
                    type: "checkbox",
                    name: "privacy_policy",
                    model: this.form.privacy_policy,
                    classes: "form-checkbox !px-2 !hover:ring-none",
                    value: 1,
                    isRequired: false,
                },
                {
                    componentType: "Label",
                    forInput: "privacy_policy",
                    labelText: "Datenschutzerklärung zustimmen*",
                    htmlAfter: "</div> </div> </div>",
                },
            ],
        ],
    },
},

CodePudding user response:

you can use v-html in your vue file and put there html you can see in vue doc

CodePudding user response:

I have solved the problem like this:

//Vue component to render dynamically created contact form fields

<Field v-for="(children, index) in fields" :key="index"
       
       :
>
    <variable-render v-for="(child) in children" v-bind="child"/>
</Field>

//contact form fields to render

fields: [
    [
        {
            componentType: "FormLabel",
            forInput: "category",
            labelText: "Was ist das Thema Ihres Anliegens?"
        },
        {
            componentType: "div",
            class: "grid justify-center",
            children: [
                {
                    componentType: "div",
                    class: "flex mt-3 flex-row items-center space-x-4",
                    children: [
                        {
                            componentType: "FormInput",
                            type: "radio",
                            id: "offer",
                            name: "category",
                            value: "offer",
                            class: "opacity-0 absolute left-1/2 peer",
                            model: this.form.category,
                        },
                        {
                            componentType: "FormLabel",
                            forInput: "offer",
                            class: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
                            labelText: "Fragen zum Angebot",
                        },
                    ]
                },
                {
                    componentType: "div",
                    class: "flex mt-3 flex-row items-center space-x-4",
                    children: [
                        {
                            componentType: "FormInput",
                            type: "radio",
                            id: "business",
                            name: "category",
                            value: "business",
                            class: "opacity-0 absolute left-1/2 peer",
                            model: this.form.category,
                        },
                        {
                            componentType: "FormLabel",
                            forInput: "business",
                            class: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
                            labelText: "Geschäftliche Anfrage",
                        },
                    ]
                },
                {
                    componentType: "div",
                    class: "flex mt-3 flex-row items-center space-x-4",
                    children: [
                        {
                            componentType: "FormInput",
                            type: "radio",
                            id: "technical",
                            name: "category",
                            value: "technical",
                            class: "opacity-0 absolute left-1/2 peer",
                            model: this.form.category,
                        },
                        {
                            componentType: "FormLabel",
                            forInput: "technical",
                            class: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
                            labelText: "Technische Probleme",
                        },
                    ]
                },
                {
                    componentType: "div",
                    class: "flex mt-3 flex-row items-center space-x-4",
                    children: [
                        {
                            componentType: "FormInput",
                            type: "radio",
                            id: "other",
                            name: "category",
                            value: "other",
                            class: "opacity-0 absolute left-1/2 peer",
                            model: this.form.category,
                        },
                        {
                            componentType: "FormLabel",
                            forInput: "other",
                            class: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
                            labelText: "Sonstiges",
                        },
                    ]
                },
            ]
        },
     ],
  ],

//VariableRender.vue

<script>
import {h, resolveComponent} from 'vue';

export default {
    name: "VariableRender",

    props: {
        componentType: String,
        children: {
            type: Array,
            default: undefined
        },
    },

    methods: {
        makeVNodeTree(childObject) {
            if (Array.isArray(childObject)) {
                let childArray = [];
                for (let i = 0; i < childObject.length; i  ) {
                    if (childObject[i].children !== undefined) {
                        let {componentType, children, route, makeVNodeTree, ...newChildObject} = childObject[i];
                        if(!this.tagIsValid(childObject[i].componentType)){
                            childArray.push(h(resolveComponent(childObject[i].componentType), newChildObject, this.makeVNodeTree(childObject[i].children)));
                        } else {
                            childArray.push(h(childObject[i].componentType, newChildObject, this.makeVNodeTree(childObject[i].children)));
                        }
                    } else{
                        let {componentType, route, makeVNodeTree, ...newChildObject} = childObject[i];
                        if(!this.tagIsValid(childObject[i].componentType)){
                            childArray.push(h(resolveComponent(childObject[i].componentType), newChildObject));
                        } else {
                            childArray.push(h(childObject[i].componentType, newChildObject));
                        }
                    }
                }
                return childArray;
            }
            if (childObject.children !== undefined) {
                let {children, componentType, route, makeVNodeTree, ...newChildObject} = childObject;
                if(!this.tagIsValid(childObject.componentType)){
                    return h(resolveComponent(childObject.componentType), newChildObject, this.makeVNodeTree(childObject.children));
                }
                return h(childObject.componentType, newChildObject, this.makeVNodeTree(childObject.children));
            }
            let {componentType, route, makeVNodeTree, children, ...newChildObject} = childObject;
            if(!this.tagIsValid(childObject.componentType)){
                return h(resolveComponent(childObject.componentType), newChildObject);
            }
            return h(childObject.componentType, newChildObject);
        },

        tagIsValid(tag) {
            let tagChecked = document.createElement(tag).toString();
            return tagChecked !== "[object HTMLUnknownElement]";
        }

    },

    render() {
        return this.makeVNodeTree(
            {
                componentType: this.componentType,
                children: this.children
            }
        );
    }
    ,
}
</script>
  • Related