vue icon indicating copy to clipboard operation
vue copied to clipboard

Provide a way to define different name for prop attribute

Open davletovalmir opened this issue 6 years ago • 17 comments

What problem does this feature solve?

In most of cases, it's not really comfortable to use initialProp as prop name, for example, or have normalizedProp inside a component, which takes some passed prop and transforms it. Code looks bloated and reminds more workaround than a good solution.

Having ability to change attribute name of prop would be great. Something like:

rawProp: { attributeName: "prop" }

What does the proposed API look like?

<component size="md"> ... </component>
computed: {
  size: {
    switch (this.rawSize) { ... } // returns something in case blocks
  }
},
props: {
  rawSize: {
    attributeName: "size",
    type: String
  }
}

Thus, using any of proposed solutions above, this.size inside component would return transformed value (for example, h4 or just 4).

I believe having this feature would be very awesome and help us to write cleaner code.

davletovalmir avatar Apr 01 '18 21:04 davletovalmir

I'm interested in this feature too. Is this feature confirmed to be implemented? I'm willing to work on this.

Edit:

I'm currently now working on this, please feel free to jump in.

hatashiro avatar Apr 19 '18 06:04 hatashiro

Besides, there's also another enhancement about props.

Here's a simple code.

props:{
  size: {
    type: Number,
  }
}

And here's a parent component:

<parent>
  <child size="1"></child>
</parent>

We know it's a wrong usage, but I think, now that we provided the field type, we can call Number(value) to change it's type?

After seeing this issue, I think maybe my choice can be a default function of his transform function.

panhaoyu avatar Apr 21 '18 14:04 panhaoyu

Regarding the transform, it's basically coerce from Vue 1 and it was removed. The feature request is about having different name locally for a prop but the transform feature has been asked many times already (#2218, https://github.com/vuejs/vue/issues/7657) and it's achievable in userland: https://github.com/posva/vue-coerce-props.

posva avatar Apr 21 '18 14:04 posva

@posva, I've updated FR description.

davletovalmir avatar Apr 24 '18 06:04 davletovalmir

To give this some life again, I am also very much interested regarding this feature. I would though call it propName to stay in line with it being props:

props: {
  rawSize: {
    propName: 'size',
    type: Number,
    default: 1,
  }
}

codebryo avatar May 14 '18 11:05 codebryo

Here is a Vue mixin (fjc0k/vue-messenger) including a series of useful enhancements to Vue components props:

Hope this helps.

fjc0k avatar Jun 15 '18 12:06 fjc0k

It's been a while, but I'm going to bring it up again, what's the status of this feature request? Is it confirmed or already implemented?

The proposed (fjc0k/vue-messenger) does not solve the issue. Again, we simply want an alias to prop names, so we wouldn't have to write initialThis, initialThat all the time.

I'm willing to work on this feature, is it confirmed/implemented?

jbieliauskas avatar Oct 13 '18 10:10 jbieliauskas

I'm also very interested in this. I just have something to point out: Currently we look at props as being a component's documentation. An alias would be just for internal use. Wouldn't it be better if aliases were a separate option? Something like:

export default {
    props: {
        size: {
            type: Number,
            default: 100
        },

        position: {
            type: Object,
            default: () => ({ x: 0, y: 0 })
        }
    },

    aliases: {
        initialPosition: 'position'
    }
}

This way, props are kept with just the information the caller needs, nothing more.

pdcmoreira avatar Dec 20 '18 12:12 pdcmoreira

Not really because it's part of the prop definition so it belongs in one property. Documentation tools can still skip it

posva avatar Dec 20 '18 13:12 posva

It seems to me that this would be preferable:

props: {
  size: {
    type: String,
    alias: "rawSize"
  }
}

Rather than this:

props: {
  rawSize: {
    type: String,
    propName: "size"
  }
}

The external facing prop name should remain as the key in the props object regardless of whether an alias is set or not. Adding an alias for internal use should simply require the addition of a property to that prop spec, not changing the property key.

Here is an example of an existing size prop which the develop later wants to alias within this component:

Original proposal:

props: {
  size: {
    type: String
  }
}

gets changed to:

props: {
  rawSize: {
    type: String,
    propName: "size"
  }
}

My suggestion:

props: {
  size: {
    type: String
  }
}

gets added to:

props: {
  size: {
    type: String,
    alias: "rawSize"
  }
}

hrobertson avatar Jan 18 '19 14:01 hrobertson

Edit: Oops, I made a mistake, I was intending to reply to vuejs/rfcs#10. But it's still valid here. I'll reply in there too.

I think the examples list in the Motivation section of the RFC (as well as some use cases commented) are not good arguments for this proposal.

  1. This example expresses its intent quite accurately, the prop name indicates that it's the initial value, which is different from the internal mutable value. I think making this distinction is preferable.
props: ['initialCounter'],
data() {
  return {
    counter: this.initialCounter
  }
}
  1. This example is a bit representative for a lot of arguments around the previously commented use cases of props coercion, sanitization or preprocessing in general.
props: ['size'],
computed: {
  normalizedSize() {
    return this.size.trim().toLowerCase()
  }
}

With the introduction of Composition API, those use cases could be handled elegantly:

props: ['size'],
setup(props) {
  const size = computed(() => {
    return props.size.trim().toLowerCase()
  })

  return {
    size
  }
}

That being said, I'm not entirely against this. The Swift example in the RFC regarding argument labels is what in the similar vein with this proposal. Take that example into the context of Vue:

props: {
  person: String,
  from: {
    as: 'hometown',
    type: String
  }
}

And take the example of the new <teleport> component (though it's not implemented with normal component options). Its target prop name is to, but it's not ideal to refer it internally as to. For the sole purpose of renaming (or aliasing), we could do it in setup function:

props: {
  to: {
    type: [String, Element]
  }
},
setup(props) {
  const target = toRef(props, 'to')

  // setting up

  return {
    target
  }
}

But it's not as expressive and cohesive as following IMO:

props: {
  to: {
    as: 'target',
    type: [String, Element]
  }
},
setup(props) {
  // setting up

  return {
    //
  }
}

So, in summary:

  1. IMHO it's a bit of a detour to use this feature to solve the problems of props preprocessing of sort.
  2. This proposal can be useful for providing the feature of argument labels.

KorHsien avatar Apr 19 '20 15:04 KorHsien

This is a cool feature. I think the idea is similar to that of how Swift allows you to have an internal variable and external parameter name. (https://useyourloaf.com/blog/swift-named-parameters/)

Sometimes it makes sense to have verbose external names for clarity, and shorter names inside the component.

For example, a component can have a long name like this:

<MyTable v-bind:userDataFromSomeAPI="data" />

but inside the component I don't want to refer to it as userDataFromSomeAPI, but just as user.

So I would really like this! I think as or alias are good, though I like as for brevity.

amerikan avatar May 23 '20 23:05 amerikan

Another use case for such alias is having components created with :is="component" where you create completely different components with different internal logic, but you pass data inside of such components with a unified prop, something like payload, but for clarity reasons you want the prop to be named differently in every component that receives it

AndrewBogdanovTSS avatar Jun 03 '20 08:06 AndrewBogdanovTSS

Something like from from provide/inject would be awesome also https://vuejs.org/v2/api/#provide-inject

inject: {
    foo: {
      from: 'bar',
      default: 'foo'
    }
}

declantsien avatar Jul 31 '20 19:07 declantsien

It's very annoying to have different names for data and props or having ugly hacks like <some-component :props="{myProp: someVal }"/> to overcome Vue limitations in this area.

bomzj avatar Nov 19 '20 10:11 bomzj

Any progress? would be a nice to have...! (my use case is to support international developers, so the prop name is more intuitive in each language)

as a workaround: (in the meantime) add a new prop for every alias, and then using computed value ... but it adds more lines to the component (compared to a simple one line as @hrobertson suggested with: props: { size: { type: String, alias: "rawSize" } }

mleathem avatar Jul 23 '21 08:07 mleathem

Another use case for such alias is having components created with :is="component" where you create completely different components with different internal logic, but you pass data inside of such components with a unified prop, something like payload, but for clarity reasons you want the prop to be named differently in every component that receives it

This is my use case. Currently what I do isn't terrible, just looking for more elegance and eliminating one extra variable:

<component :is="component" :payload="data" />

With 20 components or so, and inside any given component pass prop payload into a const.

Example: Customer component:

const props = defineProps<{
    payload: any
}>()
const Customer = computed(() => props.payload)

Which allows me to use Customer in the template, and not payload peppered everywhere.

kalnode avatar Jan 10 '24 22:01 kalnode