1. Props

 

1.1. What are props?

  • In many cases, a parent component needs to give values to a child component.
  • For example, one can easily imagine a component acting as a navigation bar whose items are provided by its parent.
  • This passing of values is done thanks to the principle of props, meaning the properties of the child component, whose value the parent can set.
  • Props nonetheless remain variables local to a component, like those defined with ref() or reactive(). They are therefore not directly accessible from outside the component.

 

1.2. defining props

  • To define props-type variables of a component, you simply call the defineProps() function in the script part, whose parameter is:
    • either an array containing only the names of the variables,
    • or an object whose fields are the names of the variables and their value a JS type (String, Number, Boolean, Array, Object, Function, ...)
  • The second syntax should be preferred because it allows warning messages in the console when the parent component gives a value of the wrong type to a prop.

Example with 2 props named title and show:

<script setup>
...
const props = defineProps({
  title: String,
  show: Boolean
})
  ...
</script>

 

Remarks:

  • There is no need to import defineProps().
  • You are not required to retrieve the return value of this function. This is only useful when you need to access the props in the script part.
  • If you retrieve the return value, you put it in a variable generally named props. However, you can name it differently, provided you then use that name in the script.

 

1.3. Manipulating props

  • Props are not manipulated quite like local variables defined with ref or reactive. It depends on the context:
    • in the template: you use the prop's name directly
    • in the script, you use the prop's name, preceded by the name of the variable that stores the return value of defineProps().

Example (in CompoFils.vue):

<template>
  {{ title }}
</template>
<script setup>
const props = defineProps({ title: String, happy: boolean})
console.log(props.title); console.log(props.happy)
...
</script>

 

  • To set their value in the parent component, this happens when you use the tag that creates the child component. You simply give a value to an attribute bearing the prop's name.
  • From the parent's point of view, the prop is therefore an attribute of the child.
  • To set the value of the attribute representing the prop, it works like with other attributes.
  • You can:
    • either give a static value, as you would in HTML. For example: oneprop="hello",
    • or give a value coming from a variable of the parent component, thanks to v-bind. For example: v-bind:oneprop="myvar"

 Example (in CompoParent.vue):

<template>
  <CompoFils title="bonjour" :happy="state">
</template>
<script setup>
import {ref} from 'vue'
import CompoFils from '@/components/CompoFils.vue'
const state = ref(false)
...
</script>

 

WARNING!

  • Modifying the value of a prop in the component that declares it is normally forbidden, although it is possible. In that case, you get a warning message in the console.
  • Moreover, except in special cases, if a prop is modified, this modification will not be reflected in the parent component.

 

2. Events

2.1. Setting up an event listener: v-on

 

  • In basic JS, you set up an event listener on a tag thanks to attributes of the onXXX kind, for example onclick.
  • The value of this attribute is generally simple javascript code, for example a call to a function that will handle the event.
  • Vuejs offers the v-on directive to obtain the same result.
  • The difference is that v-on is parameterizable by the type of event you want to listen to and that its value is a javascript expression (like for mustaches, v-bind, ...) directly accessing the data/methods (see below) of the vue instance.
  • The syntax is: v-on:event_name="JS expression"
  • As with v-bind, there is a shorthand notation: @event_name="JS expression"

Remark: if you set up an event capture and the latter is never generated, this has no impact on execution.

 

2.2. Retrieving the event

  • It is relatively common for the event listener to call a function taking as a parameter a value drawn from the component that generated the event.
  • For example, when an input field is validated (change event), you want to retrieve its value to give it as a parameter to the function that will process the event.
  • For this, you need to retrieve the event object. Vuejs provides a global variable $event, referencing the current event object.
  • Thanks to this variable, you notably have access to the target component of the event: $event.target.
  • You can then access the attributes, for example for an input field: $event.target.value.

 

2.3. Emitting an event

  • In the template, vuejs offers a $emit() function that allows you to explicitly generate an event, with a name and a value set by the programmer.
  • It is therefore possible to create events different from those defined in the HTML/JS standard.
  • You can use this function both in the <template> part and the <script> part (in the latter case, don't forget to prefix with this.)
  • The syntax is: $emit("event_name", value)

 

  • In the script part, this function is not available and you must explicitly declare the events with the defineEmits() function.
  • This function takes by default an array of strings as a parameter. Each string represents an event name used in the script part.
  • This function returns a function, which you can name as you wish and which serves as an equivalent of $emit(), with the same principles. Generally, you name this function emit.

Example:

<template>
  ...
  <button @click="$emit('myevent', 1)">bouton 1</button>
  <button @click="sendEvent">bouton 2</button>
  ...
</template>
<script setup>
...
const emit = defineEmits(["myevent"])
function sendEvent() {
  emit("myevent", 2)
}
...
</script>

 

  • Whether the child component emits an event from the template or the script, capturing this event in the parent component is done as with native events: you simply use @event_name.

WARNING:

  • unlike classic HTML events which bubble up from child to parent, until reaching the window object, events created with vuejs only bubble up to the parent of the component that emitted the event.
  • if this event must bubble up one more level, the parent must explicitly re-emit the event by also using $emit.
 
2.4. Relationship with props
 
  • We have seen that a child component has no way to directly modify the value of its props, because their value is given by the parent component.
  • However, it is relatively common for a user interaction in the child to imply a change in the value of the prop.
  • Take for example, a generic child component that displays a list of selectable items thanks to a checkbox.
  • This component has as props an array of objects representing the items of the list, and an array of booleans indicating which items are selected. These two arrays are provided by the parent component.
  • It goes without saying that if the user checks or unchecks a box, this array of booleans must be updated.
  • Unfortunately, this is not directly possible.
  • On the other hand, it is possible indirectly thanks to events: the child simply sends its parent an event indicating which box changed state.
  • The parent captures the event and updates its array of booleans which it gives to its child as a prop. As a result, the child's prop is updated.

 

2.5. What about events propagating downward?
 
  • Suppose 3 components with A the main component, B and C child components.
  • How do you make an action in B imply a modification in C?
  • It would be quite handy to be able to emit events with $emit from a parent component to a child component.
  • Unfortunately, this is impossible. It is also impossible to emit an event between "sibling" or "cousin" components.
  • The only viable solution with the basic mechanisms of vuejs is to use the principle of props.
  • To give the main idea:
    • component A serves as a storage point for the data "common" to B and C, as well as the methods allowing this data to be modified.
    • to simplify, we assume that component B offers actions on this data, while C displays this data.
    • for C to have access to the data, A will share it in the form of a prop, that is to say a variable in C that will be added to those of data and computed, but whose value is provided by A.
    • when an action is triggered in B, the latter emits an event that A captures, then it calls a function modifying the data.
    • since this data is shared with C, any modification in A will be reflected in C, so its display will be refreshed.