Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a vue.js equivalent of ngTemplateOutlet?

Does vue.js have an equivalent of Angular's *ngTemplateOutlet directive? Let's say I have some components defined like this:

    <template>
        <div id="independentComponent">
            Hello, {{firstName}}!
        </div>
    </template>
    <script>
        export default {
            name: "independentComponent",
            props: ['firstName']
        }
    </script>

    ...

    <template>
        <div id="someChildComponent">
            <slot></slot>
            <span>Let's get started.</span>
        </div>
    </template>
    <script>
        export default {
            name: "someChildComponent"
        }
    </script>

I want to be able to do something like this:

<template>
    <div id="parentComponent">
        <template #indepdentInstance>
            <independentComponent :firstName="firstName" />
        </template>
        <someChildComponent>
            <template #indepdentInstance></template>
        </someChildComponent>
    </div>
</template>
<script>
    export default {
        name: "parentComponent",
        components: {
            someChildComponent,
            independentComponent
        },
        data() {
            return {
                firstName: "Bob"
            }
        }
    }
</script>

In Angular, I could accomplish this with

<div id="parentComponent">
    <someChildComponent>
        <ng-container *ngTemplateOutlet="independentInstance"></ng-container>
    </someChildComponent>

    <ng-template #independentInstance>
        <independentComponent [firstName]="firstName"></independentComponent>
    </ng-template>
</div>

But it looks like Vue requires the element to be written to the DOM exactly where it is in the template. Is there any way to reference an element inline and use that to pass to another component as a slot?

like image 715
asker11660 Avatar asked Oct 31 '18 19:10

asker11660


People also ask

Does Vue have services like Angular?

Reactivity of servicesYour services are stateful, but they are not reactive, like Angular. It means updating you service variables will not trigger change detection (thus, no UI update).

What is VueJS similar to?

React, jQuery, Bootstrap, Angular 2, and AngularJS are the most popular alternatives and competitors to Vue. js.

Is Vue JavaScript a spa?

Learn what a single-page application (SPA) is, why VueJS is one of the leading JavaScript frameworks for creating a SPA, and how to connect to Sanity using its JavaScript client to create a web application with low maintenance.

Is VueJS gaining popularity?

Vue is considered a child of the JavaScript frameworks Angular and React. Created by Evan You in 2013 (released in 2014), Vue has gained popularity rapidly. It's worth noting that Vue doesn't have support from big companies like Google (Angular) or Facebook (React).


2 Answers

You cannot reuse templates like ngTemplateOutlet, but can combine idea of $refs, v-pre and runtime template compiling with v-runtime-template to achieve this.

First, create reusable template (<ng-template #independentInstance>):

<div ref="independentInstance" v-show="false">
    <template v-pre> <!-- v-pre disable compiling content of template -->
        <div> <!-- We need this div, because only one root element allowed in templates -->
            <h2>Reusable template</h2>
            <input type="text" v-model="testContext.readWriteVar">
            <input type="text" v-model="readOnlyVar">
            <progress-bar></progress-bar>
        </div>
    </template>
</div>

Now, you can reuse independentInstance template:

<v-runtime-template
    :template="$refs.independentInstance.innerHTML"
    v-if="$refs.independentInstance">
</v-runtime-template>

But keep in mind that you cannot modify readOnlyVar from inside independentInstancetemplate - vue will warn you with:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "readOnlyVar"

But you can wrap it in object and it will work:

@Component({
    components: {
        VRuntimeTemplate
    }
})
export default class ObjectList extends Vue {
    reusableContext = {
        readWriteVar: '...'
    };

    readOnlyVar = '...';
}

like image 196
NekitoSP Avatar answered Oct 10 '22 22:10

NekitoSP


You could try Portal vue written by LinusBorg a core Vue team member.

PortalVue is a set of two components that allow you to render a component's template (or a part of it) anywhere in the document - even outside the part controlled by your Vue App!

Sample code:

<template>
  <div id="parentComponent">
    <portal to="independentInstance">
      <!-- This slot content will be rendered wherever the <portal-target>
           with name 'independentInstance' is located. -->
      <independent-component :first-name="firstName" />
    </portal>
    
    <some-child-component>
        <portal-target name="independentInstance">
          <!--
          This component can be located anywhere in your App.
          The slot content of the above portal component will be rendered here.
          -->
        </portal-target>
    </some-child-component>
  </div>
</template>

There is also a vue-simple-portal written by the same author that is smaller but that mounts the component to end of body element.

like image 28
logee Avatar answered Oct 10 '22 21:10

logee