1

I'm currently building a component in vue.js and I have a bit of a problem. You see, there's a lot of parameters you can give to my component, so for the sake of clarity, I decided to go with the approach below:

<script type="text/javascript">
    Vue.$noClientConf = {
    'cmp_name':         'NoClient', 
    'cmp_title':        'Selection du client',
    'url':              'ajax/getclients.php',
    'parent':           null,
    'opt_texte':        'NomClientFR',
    'opt_valeur':       'NoClient',
    'cmp_max_options':  3,
    'opt_custom':       null,
    'data_size':        10,
    'data_style':       'btn btn-default btn-sm',
    'data_live_search': 'true'
    };
</script>

<div id="app">

  <div class="col-lg-2">
    <flex-select ref="NoClient" :conf="Vue.$noClientConf"></flex-select>
  </div>

</div>

<script type="text/javascript">
    var app = new Vue({
      el: "#app",
      data:{Vue}
    });
</script>

Basically, I define an object containing the necessary parameters and I give that to my component. The thing is that I'd like to define some default values for some of these parameters so that the user wouldn't have to list them all.

Now, I've read about Vue.js props validation and find it would fit extremely well with what I'd like to do. However, while you can validate if a prop is an object, it doesn't seem like you can validate the object's structure. For example, I'd like to be able to do:

props: {
        config.cmp_name: {
            type:String,
            required: true
        },
        config.cmp_title:{
            type:String,
            required: true
        }
    }

So my question is basically... is there a way to do the above?

Osuwariboy
  • 1,335
  • 1
  • 14
  • 29

2 Answers2

2

Use the object binding syntax.

<flex-select ref="NoClient" v-bind="defaults"></flex-select>

That will pass all the properties of defaults and just validate the ones you need.

props: {
  cmp_name: {
    type:String,
    required: true
  },
  cmp_title:{
    type:String,
    required: true
  }
}

Otherwise you can use a function as a custom validator.

props:{
  conf: {
    validator(config){
      let cmp_name = config.cmp_name && typeof config.cmp_name === "string"
      let cmp_title = config.cmp_title && typeof config.cmp_title === "string"
      return cmp_name && cmp_title
    }
  }
}

FWIW, I'm not able to get Vue.$noClientConf to work at all in an example. Instead, I just created a defaults object.

console.clear()

const defaults = {
  'cmp_name':         'NoClient', 
  'cmp_title':        'Selection du client',
  'url':              'ajax/getclients.php',
  'parent':           null,
  'opt_texte':        'NomClientFR',
  'opt_valeur':       'NoClient',
  'cmp_max_options':  3,
  'opt_custom':       null,
  'data_size':        10,
  'data_style':       'btn btn-default btn-sm',
  'data_live_search': 'true'
};

Vue.component("flex-select",{
  props: {
  cmp_name: {
    type:String,
    required: true
  },
  cmp_title:{
    type:String,
    required: true
  }
},
  template:`
    <div>{{cmp_name}} {{cmp_title}}</div>
  `
})

new Vue({
  el:"#app",
  data:{
    defaults
  }
})
<script src="https://unpkg.com/vue@2.2.6/dist/vue.js"></script>
<div id="app">
  <flex-select v-bind="defaults"></flex-select>
  {{defaults}}
</div>
tony19
  • 125,647
  • 18
  • 229
  • 307
Bert
  • 80,741
  • 17
  • 199
  • 164
  • The un-minified version of Vue is not aware of itself by name, so you might want to check this post [here](https://stackoverflow.com/questions/44267239/how-to-pass-a-javascript-object-to-component-in-vuejs/44268061?noredirect=1#comment76929437_44268061) for the solution. Other than that, your solution works perfectly. Thanks :) – Osuwariboy Jul 12 '17 at 18:58
0

If you want to use custom validator, a best practice is to use Set() object.

Example:

Object input needed by ExampleComponent component:

const obj = {
    block1: {
      icon: 'example',
      title: 'example',
      content: 'example'
    },
    block2: {
      icon: 'example',
      title: 'example',
      content: 'example'
    }
  };

Component with custom validator:

export default {
    name: 'ExampleComponent',
    props: {
      data: {
        type: Object,
        validator: (o) => {
          const set = new Set();
          set.add(!!(o.block1 && o.block1.icon && typeof o.block1.icon === 'string'));
          set.add(!!(o.block1 && o.block1.title && typeof o.block1.title === 'string'));
          set.add(!!(o.block1 && o.block1.content && typeof o.block1.content === 'string'));
          set.add(!!(o.block2 && o.block2.icon && typeof o.block2.icon === 'string'));
          set.add(!!(o.block2 && o.block2.title && typeof o.block2.title === 'string'));
          set.add(!!(o.block2 && o.block2.content && typeof o.block2.content === 'string'));
          return !set.has(false);
        },
      },
      color: {
        type: String,
        validator: value => ['black', 'white'].includes(value),
      },
    },
  };

tony19
  • 125,647
  • 18
  • 229
  • 307
Dimitri
  • 922
  • 2
  • 13
  • 34