1

I am trying to populate a NativeScript-Vue ListView with templates that contain components of which their types are not known ahead of time. For example, this code does not work as NativeScript does not have a 'component' element but this suggests what I am trying to accomplish:

<ListView for="component in components">
    <v-template>
        <component :is="component" />
    </v-template>
</ListView>

computed: {
    components () {
        return ['Label', 'Button'];
    }
}

Yes, I know you can use if="" in a v-template, but in this case I do not know ahead of time what components need to be loaded in the ListView. In my case I am loading global components in a plugin, and these components will be referenced in the ListView.

2 Answers 2

2

Thanks @Manoj. Those wise words made me think, the template can't be dynamic but the contents of the v-template can be. Maybe not for everyone, but this code works for me:

// App.vue

<template>
    <Page>
        <ActionBar title="Welcome to NativeScript-Vue!"/>
        <GridLayout columns="*" rows="400,*">
            <ListView ref="lv" for="item in items">
              <v-template>
                <v-component :type="item.type" :options="item.options" />
              </v-template>
            </ListView>
        </GridLayout>
    </Page>
</template>

<script lang="ts">
  import Vue from 'nativescript-vue'
  import { Component } from 'vue-property-decorator'
  import VComponent from './VComponent.vue'

  @Component({
    components: {
      VComponent
    }
  })
  export default class App extends Vue {
      get items () {
      return [
        {type: 'Label', options: [{key: 'text', value: 'I am a Label'}, {key: 'color', value:'red'}] },
        {type: 'Button', options: [{key: 'text', value:'I am a Button!'}]}
      ]
    }
  }
</script>


// VComponent.vue

<template>
  <StackLayout ref="myLayout">
  </StackLayout>
</template>

<script lang="ts">
  import Vue from 'nativescript-vue'
  import { Component, Prop } from 'vue-property-decorator'
  import { StackLayout } from 'tns-core-modules/ui/layouts/stack-layout'
  import { Label } from 'tns-core-modules/ui/label'
  import { Button } from 'tns-core-modules/ui/button'

  const classByClassName = {
    'Label': Label,
    'Button': Button
  }

  @Component
  export default class CoolTemplate extends Vue {
    @Prop() type!: string;
    @Prop() options;

    mounted () {
      if (this.type) {
        const myLayout = <StackLayout>((<Vue>this.$refs.myLayout).nativeView)
        const component = new classByClassName[this.type]
        for (var i = 0; i< this.options.length; i++) {
          const option = this.options[i];
          component[option.key] = option.value 
        }
        myLayout.addChild(component)
      }
    }

  } 
</script>
Sign up to request clarification or add additional context in comments.

Comments

1

Your template can not be dynamic, that's the whole point of using ListView - keeping them static, so they can be reused as needed. If you like to see different components based on data then you must use multiple templates.

Read more on docs.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.