0

We are using Vue.js, very nice framework if you ask me. From Knockout.js and WPF I know that a context can be specified for the bindings. How can this be done with Vue.js?

See the example below. Here binding-context is pseudo code for the functionality I am looking for in Vue.

Vue.component('hosting-setup', {
template:
    '<wizard>' +
        '<wizard-step binding-context="step1" :title="title">' +
            '<select :options="choices"></select>' +
        '</wizard-step>' +
        '<wizard-step binding-context="step2" :title="title">' +
            '<select :options="choices"></select>' +
        '</wizard-step>' +
    '</wizard>',

    data: function () {
        return {
            step1: {
                title: 'Choose virtualization software',
                choices: ['Virtual Box', 'VMWare'],
                choice: undefined,
            },
            step2: {
                title: 'Choose guest operating system',
                choices: ['Debian 6', 'Ubuntu 16', 'Windows Server 2012'],
                choice: undefined
            }
        };
    }
});
Mike de Klerk
  • 11,906
  • 8
  • 54
  • 76

3 Answers3

1

There is no "with" binding equivalent in Vue. There are a few approaches for what you want to do, but for your example I would use a computed to return your data as an array and then use v-for to print out each component passing the relevant data as a prop:

Vue Instance

Vue.component('wizard-step', {
  template: `<div>{{title}}</div>`,
  props: ['title']
});

new Vue({
  el: '#app',
  computed: {
    wizardSteps() {
      return [this.step1, this.Step2]
    }
  },
  data() {
    return {
      step1: {
        title: 'Choose virtualization software',
        choices: ['Virtual Box', 'VMWare'],
        choice: undefined,
      },
      Step2: {
        title: 'Choose guest operating system',
        choices: ['Debian 6', 'Ubuntu 16', 'Windows Server 2012'],
        choice: undefined
      }
    };
  }
})

Markup

  <wizard-step :title="step.title" v-for="(step, index) in wizardSteps" :key="index"></wizard-step>

Here's the JSFiddle: http://jsfiddle.net/craig_h_411/vzq25go5/

EDIT

If you want to pass the data down to the component directly, you can use v-bind to pass the object and declare the object property names you want to use in the component as props, which maybe gets closer to what you are asking for, so:

Vue.component('wizard-step', {
  template: `<div>
    {{title}}
    <select>
      <option v-for="choice in choices" >{{choice}}</option> 
    </select>
  </div>`,
  props: ['title','choices']
});

Parent markup

  <wizard-step v-bind="step1"></wizard-step>
  <wizard-step v-bind="Step2"></wizard-step>

Here's the JSFiddle for that: http://jsfiddle.net/craig_h_411/7dg41j0w/

craig_h
  • 31,871
  • 6
  • 59
  • 68
  • Thank you for your answer. The given code example is actually completely made up for the purpose of this question. The given v-for does not seem to be applicable in our case. – Mike de Klerk Oct 30 '17 at 14:13
  • +1 because I wasn't aware of the v-bind. It doesn't however feels completely satisfactory because creating components solely for the purpose of not having to specify the full data property path seems kind of cumbersome. I could apply v-bind in some code I have written some time earlier though, where I created components for the sake of separation of concerns anyway. – Mike de Klerk Oct 30 '17 at 14:52
0

If you have really nested child, can try to cheat using v-for with 1 item array.

<template v-for="local in [data.nest1.nest2.nest3]">
    //normal binding using local.XXXX
</template>
Yiping
  • 971
  • 10
  • 31
0

Tested in Vue 2.6.10:

<template>
    <wizard>
        <wizard-step v-if="props.step1 ? step = props.step1 : false" :title="step.title">
            <select :options="step.choices"></select>
        </wizard-step>
        <wizard-step v-if="props.step2 ? step = props.step2 : false" :title="step.title">
            <select :options="step.choices"></select>
        </wizard-step> 
    </wizard>
</template>

NOTE: Even better, for more concise code you could create a sub-component just for and pass title and options:

I.e.

<template>
    <wizard>
        <wizard-step v-if="props.step1" :step="props.step1" />
        <wizard-step v-if="props.step2" :step="props.step2" />
    </wizard>
</template>

and your child wizard-step will be:

<template>
    <wizard-step :title="step.title">
        <select :options="step.choices"></select>
    </wizard-step>
</template>

And another improvement, if you are in control on how the data returned is structured, you could return an array of steps (instead of step1 and step2), and you could just simplify further with a for-each:

<template>
    <wizard>
        <wizard-step v-for="step in props.data" :step="step" />
    </wizard>
</template>
Developer
  • 194
  • 2
  • 4