Reputation: 131
I have two sibling components where one relies on the other for an event to happen. In this case, I want to apply this styling - marginTop = "-20px";
to the div of one component when the length of an input inside another component is more than 0 characters.
Whether it be props, slots, refs or events, I'm still not sure what fits this use case (I'm very new to Vue). I'm also not sure if I can even pass data between these two sibling components directly or if I have to pass from one child to the parent and then to the other child.
What I'm currently attempting to do is to simply grab the element I want to apply the style to (in the vanilla JS way) and have the method invoked when the aforementioned condition becomes true (all in the same component).
// Component trying to style the element
<ais-state-results v-if="input.length > 0">
// Component trying to style the element
data() {
return {
input: ""
}
}
mounted() {
this.positionSecondaryContent();
},
methods: {
positionSecondaryContent() {
const secondaryContent = document.querySelector('.secondary-content');
secondaryContent.style.marginTop = "-20px";
}
},
// Component that has the element to be styled
<template>
<div class="secondary-content">
<TheWordOfTheDay />
<SuggestTranslationForm />
</div>
</template>
Aside from not knowing if I really should be communicating with other components, I'm not sure what to write in the ais-state-results
component instance above to attach it to my method and then have the method run as soon as the condition is met.
Edit
I've included the property I want to check the length of in the second code box - (data() { return { input: "" } }
What I probably didn't make clear is that I want to dynamically style an element from one component <div class="secondary-content"></div>
based on the input length of a property from another component input: ""
but I don't how to link the two together.
Upvotes: 0
Views: 747
Reputation: 90038
Vue is state driven.
In other words, you should only care about updating the controller/state and Vue will take care of updating DOM.
Here's how applying style conditionally typically looks like in Vue:
const { createApp, computed, reactive, toRefs } = Vue;
createApp({
setup() {
const state = reactive({
someCondition: false,
divStyle: computed(() =>
state.someCondition ? { marginTop: "-20px" } : null
),
});
return { ...toRefs(state) };
},
}).mount("#app");
.my-div {
border: 1px solid red;
transition: margin-top 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
body {
padding: 2rem;
}
label {
cursor: pointer;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js"></script>
<div id="app">
<div :style="divStyle" class="my-div">This is a test</div>
<label>
<input type="checkbox" v-model="someCondition" />Apply negative margin
</label>
<pre v-text="{ someCondition, divStyle }" />
</div>
The computed
divStyle
updates based on current value of someCondition
. When true
, it returns the negative margin. When false, it returns null
.
The main takeaway here is I'm not updating the view/DOM. Vue does it for me. All I do is change the values of the controller.
Update, after you've clarified the logic:
Considering this use-case, having the input in a child component seems an unnecessary complication. You should have the negative margin and the input in the same component.
But, let's say we're not talking about this particular case and we're talking about a case where you really need the child to update the parent.
There are multiple ways of sharing state across components:
reactive()
object. Simply put, reactive objects are not restricted to usage inside components. They can be external and imported in multiple components.useStuff()
function which is the typical solution for sharing any functionality (including reactive state) across multiple components in Compostion API. Reactivity could also be provided by ref()
, instead of reactive()
.The above list is not exhaustive. You also have provide/inject, globalProps, just to name two more. You could also use event driven patterns (e.g: event bus, rxjs) but those are typically considered a depart from Vue's principles, although they can be used in Vue.
Upvotes: 1