I Have component A and Component B
in component A i have an API call.
when i passing info to my component b:
<B :structuresMetaData="structureTree"></B>
Inside mounted the variable structuresMetaData the length is 0
and inside the watch the length is 1.
my issue that mounted appear before the watch.
is it would be right to put all my code in watch ? if not what is the solution ?
It looks like structureTree is being changed after <B> is created/mounted.
You have two options depending on your use case:
The first option is to defer the creation of <B> until your data is loaded. This way you don't need <B> to watch for changes to the prop and the prop will be fully populated in the created/mounted hook. This is the simpler approach.
Assuming structureTree is initially an empty array:
<B
v-if="structureTree.length > 0"
:structuresMetaData="structureTree"
/>
created() {
// this.structuresMetaData is a non-empty array here
}
I usually initialize my data with null so that I can distinguish between "not loaded" and "loaded" (where "loaded" can actually be an empty array if the data I fetched from the API was empty).
The second way is using a watcher in <B> to react to changes to the prop. You will need to do this method if the bound prop might change multiple times and you need <B> to update in some way to that change.
watch: {
structuresMetaData(value) {
// React to the change, load secondary data, etc
}
}
What exactly are you doing in <B> that requires a watcher? It's best to avoid explicit watchers if you can avoid them because it usually means you are copying data around and it gets messy when you don't have a single source of truth. Use pure computed properties whenever you can if you just want to transform the data in some way.
I'm using Vue-Formulate's Repeatable Groups. For my requirements:
A group is optional to add
If a button is pressed to add a group, then the fields in the group must be validated
The form should not initially show the group; it should show the button to add a group
For example, the desired initial appearance is in the following screenshot, which I generated after clicking the "remove" / X button in the linked codesandbox:
I've mocked this up at codesandbox here: Vue Formulate Group with Button to Start
Is this possible? If so, how?
May 2021 UPDATED WORKAROUND
In #braid/vue-formulate#2.5.2, the workaround below (in Research: A hack that seems to UPDATE: USED TO work) no longer works, using a slot to override the close button, save a ref, and trigger a click does. See also the related feature request at https://github.com/wearebraid/vue-formulate/issues/425.
<script>
export default {
// ... fluff omitted
async mounted() {
await this.$nextTick();
if (!this.hasMessages) {
// See also feature request at https://github.com/wearebraid/vue-formulate/issues/425
this.$refs.closeButton.click();
}
},
};
</script>
<template>
<FormulateInput
type="group"
name="rangeMessages"
:minimum="0"
repeatable>
<!-- See https://vueformulate.com/guide/inputs/types/group/#slots -->
<template #remove="{removeItem}">
<button ref="closeButton" #click.prevent="removeItem"/>
</template>
</FormulateInput>
</template>
Research - Vue-Formulate's Docs
In Vue-Formulate's docs on input with type="group"'s props and slots, there is a minimum prop. I've set that to zero, but that doesn't change the initial appearance. I do see multiple slots, but I'm not quite sure which one to use or if I could use any of them to achieve what I want; it seems like default, grouping, and repeatable might be useful in preventing the initial display of the first group.
Research - Vue-Formulate's Tests
I see that FormulateInputGroup.test.js tests that it('repeats the default slot when adding more', so the default slot is the content that gets repeated. According to the docs, the default slot also receives the index as a slot prop, so that could be useful.
Research - Vue Debugger
The item which I want to initially remove is at FormulateInputGroup > FormulateGrouping > FormulateRepeatableProvider > FormulateRepeatable > FormulateInput:
When I remove the initial item to match the desired initial layout, the group hierarchy changes to:
<FormulateInput><!-- the input type="group" -->
<FormulateInputGroup>
<FormulateGrouping/>
<FormulateAddMore>...</FormulateAddMore>
</FormulateInputGroup>
</FormulateInput>
Based on this change, I would expect that I need to modify FormulateGrouping to get the desired initial appearance, but I haven't found in the source what items are available to me there.
Research: A hack that seems to UPDATE: USED TO work
This hack worked in v2.4.5, but as of 2.5.2, it no longer works. See top of post for an updated workaround.
In the mounted hook, when I first render the form, I can introspect
into the formValues passed to v-model to see if the group lacks an
initial elements that is filled out. If so, then I can make use of a
ref msgs on the FormulateInput of type group to then call
this.$refs.msgs.$children[0].$children[0].removeItem(), which
triggers an initial remove of the (empty) item. This is super hacky,
so I'd prefer a better way, but it kind of works. The only problem is
that it validates the fields when clicking on the button, before any
input has been entered.
This is a fair question, and Vue Formulate used to support the behavior of just using an empty array to begin with, however it became clear that it was confusing to users that their fields would not show up without an empty object [{}] when they bound the model, so a change was made to consider an initial value of an empty array an "empty" field and pre-hydrate it with a value. Once that initial hydration is completed however, you can easily re-assign it back to an empty array and you're good to go. This is easily done in the mounted lifecycle hook:
...
async mounted () {
await this.$nextTick()
this.formData.groupData = []
}
...
Here's a fork of your code sandbox: https://codesandbox.io/s/vue-formulate-group-with-button-to-start-forked-32jly?file=/src/components/Reproduction.vue
Provided solutions weren't working for me but thanks to previous answer I've managed to find this one:
mounted(){
Vue.set(this.formData, "groupData", [])
},
which does same effect as
data(){
formData: {
groupData: [],
},
},
mounted(){
this.formData.groupData = []
},
I have an Order form component which uses a OrderTasklistBuilder component. Note: there are nested components here. The hierarchy is as follows: OrderSingle > CreateOrderForm > OrderTasklistBuilder
The initial order is fetched when the OrderSingle is mounted and then passed down through child components.
The tasklist builder component is used like this:
<order-tasklist-builder v-if="form.tasks.length" :initial-tasks="form.tasks" #taskAdded="handleTaskAdded" class="mb-2" />
This works fine, but if there aren't any tasks in the listbuilder, the component will not display. This is a problem because someone might remove all of the tasks.
Now, if I remove the length check on form tasks the tasklist builder component will not display any tasks even after adding new tasks.
<order-tasklist-builder :initial-tasks="form.tasks" #taskAdded="handleTaskAdded" class="mb-2" />
The components are fairly large ( > 300 lines ) so if I can elaborate on something specific, let me know.
Solved by moving logic previously in mounted function inside of CreateOrderForm component to created function.
I have a multi-step layout managed with a dynamic component
<keep-alive>
<component :is="actualStep" :status.sync="status"></component>
</keep-alive>
<button #click.prevent="prevStep">Prev</button>
<button #click.prevent="nextStep" :disabled="!status">Next</button>
status value is used to monitor the actual component status, updating its value to true or false depending on component's internal validation process, and allowing (or not) to move to next step. As an example, a component will change status to true only if all required fields are filled.
status is also changed to an initial value when component is initiated. Some components change it to true (as they don't make any validation) and some change it to the validation process result.
mounted() {
this.$emit('update:status', this.isValid); // isValid is a computed
}
However this is only happening once when the component is mounted (I guess because of keep-alive). I would need to do this every time the dynamic component changes to the actualStep. How can this be done? or is it a better way to manage dynamic components' status?
According to the React Native Docs for ListView the signature for the renderRow function has the following signature:
(rowData, sectionID, rowID, highlightRow) => renderable
However, in the ScheduleView component in the F8App app by Facebook, PureListView which renders a ListView uses a renderRow function with this signature:
renderRow(session: Session, day: number)
How is this? What am I overlooking?
Because f8 app uses flow. See https://flowtype.org/
Ok, what I didn't realize was that it's the same row data and section ID that are being passed. I thought that it was completely customized data being passed instead but upon examination of the actual data it's now clear that the data is simply grouped by time (even though the param name is day) which really is just the section ID.
Then, as agent_hunt pointed out, they are typed using flow.