Sharing property data between sister components in vue2 - javascript

I have two components Header.vue and Sidebar.vue
On Header.vue i have a button which onclick i need to change the value of property in Sidebar.vue
On Header.vue i have
template:
<a v-on:click="toggleSidebar">Toggle</a>
method:
toggleNavbar: function() {
this.toggleSidebar(this.showSidebar)
}
On Sidebar.vue
template:
<div class="sidebar sidebar_display_none" :class="showSidebar?'show':''">
Method:
created() {
this.showSidebar= this.toggleSidebar(this.showSidebar)
console.log(this.showSidebar)
}
On Mixin
toggleSidebar: function(currentState) {
return !currentState
}
Onclick Toggle button i need to show/hide Sidebar (showSidebar property is boolean)
How can i do it? Thanks

Psidom's comment above of studying vuex is spot on. In addition, you should look into props and events as another resource/skill for sharing and managing data between components.
Note I would've loved to have left this as a comment as well but I don't have the reputation for comments yet...

Related

this.$refs empty with Vue 3 Options API

In Vue 2 I used to be able to access a property on component children (rendered inside a v-for loop using this.$refs and a dynamically-assigned :ref).
The same code in Vue 3 fails, and when I log out this.$refs the object is empty.
Here I'm wanting to access an 'isOrderable' property on all children. The problem appears to be with :ref="product.id" being a variable. If I change it to ref="foobar" then I do get the last child in this.$refs.foobar. But it vue2 me an array back containing all children components.
<script>
import productItem from "./Product.vue";
export default {
props: ["products"],
components: {
'product-item': productItem
}
methods: {
addAllProducts() {
const orderable = this.products.filter((p) => this.$refs[p.id][0].isOrderable);
...
}
}
}
</script>
<template>
<form>
<div v-for="product in products" :key="product.id">
<product-item :product="product" :ref="product.id" />
</div>
<button #click="addAllProducts">Add All</button>
</form>
</template>
Obviously something changed in vue3 but I can't find any info about it. There's plenty of info on this.$refs, and but it all has to do with accessing refs from the composition API.
Any help appreciated.
In vue 3 they change how refs work with arrays, now you need to pass a function and have a state on your data to keep track of your refs https://v3-migration.vuejs.org/breaking-changes/array-refs.html#frontmatter-title.
I don't know how your code is structured but maybe there is a better solution to your problem than using refs, if the logic that toggles if a product-item is orderable lives inside the product-item component you can have an event that emits when the orderable value is changed an update an array of orderableProducts with the id of each product, you can even use that in a v-model with the multiple v-models options of vue3. in that way you don't need to hold a reference of the dom just to filter by the ones that are orderable.

Passing data from one component to another

On component1.vue I have
export default {
data () {
return {
editItemNumber: null,
editBreakdownNumber: null
}
}
On component2.vue I have a table populated by an array
On that table is an edit button. Among the item in that table is itemNumber value. Which I need to assign from that particular row clicked to the editItemNumber on component1.vue
<b-table show-empty bordered striped hover :items="itemTableList" :fields="fields">
<template slot="actions" scope="row">
<b-btn variant='success' size="sm" #click.stop="edit(row.item,row.index,$event.target)">Edit</b-btn>
</template>
</b-table>
As you see above originally all of this was on one component and I was just calling to an edit function which repopulated the v-models with that rows contents. But now with everything split among components I don't know how to edit this to do what I've been tasked with.
I've never used JavaScript, vue or much of anything beyond basic HTML. I'm a .NET dev who's been tasked with helping out on some web based work and I'm floundering. So any help is appreciated.
The preferred way to move data between components is with events.
Normally you use props to pass data from a parent component to a child, and events to pass from a child up to a parent.
So the editmethod of C2 can be something like
edit(item, index, target) {
const payload = {
item,
index,
target
};
this.$emit('edit', payload);
}
Then you just have to listen to that event in C1. Notice the #edit attribute: that means when the edit event is fired from component-one, run my "edit" method.
<template>
<div>
<p>{{ editItemNumber }}</p>
<component-two #edit="edit" />
</div>
<script>
export default {
data () {
return {
editItemNumber: null,
editBreakdownNumber: null
};
},
methods: {
edit(eventPayload) {
this.editItemNumber = eventPayload.item.editItemNumber
}
}
</script>
If you both C1 and C2 are children of the same parent P the idea is the same, except C1 can't listen directly to C2. Instead P will listen to the edit event and pass the needed changes down to C1 through its props.
The docs on components are really good, pay special attention to the sections on props and custom events.
https://v2.vuejs.org/v2/guide/components.html

Parent / Child components VUE.JS 2.1.6 data passing

I'm very confused about how to properly tie components together.
I have two components registered globally:
Vue.component('product-welcome-component', {
template: '#product-welcome-template',
props: ['showModal'],
onCreate(){
showModal = false;
}
});
Vue.component('product-create-modal-component', {
template: '#create-modal-template'
});
In the parent's template I included the child component like this:
<template id="product-welcome-template">
<div class="welcome-wrapper">
<div class="purpose-title"><h1 class="welcome-text">Welcome to Product Hub</h1></div>
<div class="purpose-create-btn"><button ##click="showModal = true" class="btn btn-primary btn-success create-btn">Create New Product</button></div>
<product-create-modal-component v-if="showModal"></product-create-modal-component>
</div>
</template>
The problem is (one of them) is that my create-modal-component is always showing, regardless of the value of showModal, in fact i can put in v-if="1 === 2" it would still show.
I'm sure this is not the right way of registering parent / child components but I can't seem to find a proper example. Mostly what i see that the parent is the app instance and it has a child of 'child' component and then they can communicate.
I have a feeling that including the child component in the parent's template is bad practice as it makes the parent strongly coupled.
Any help would be appreciated, thank you!
You are having showModal as props to product-welcome-component, but you are trying to set it false in created, but you have to use this in created to access showModal, like following:
Vue.component('product-welcome-component', {
template: '#product-welcome-template',
props: ['showModal'],
onCreate(){
this.showModal = false;
}
});
However you are saying product-create-modal-component shows even you do v-if="1 === 2", which should not be the case Can you create a fiddle of your case.

EmberJs - Is there a way to tell ember to insert the main-view after the rootElement?

Hi I would like to know if the is a way to tell ember to initialize immediately after the root Element?
For example I have this DOM Structure:
<div id="#bodyContent" class="ember-application">
<div data-name="ContentPlaceHolderMain">
</div>
<div id="ember357" class="ember-view">
</div>
</div>
But I Want ember to be first on the DOM:
<div id="#bodyContent" class="ember-application">
<div id="ember357" class="ember-view">
</div>
<div data-name="ContentPlaceHolderMain">
</div>
</div>
In my enviroment.js file I have this line:
ENV.APP.rootElement = "#bodyContent";
Is there any way to achieve this?
Ember uses appendTo to insert it's view inside root element. But you could override didCreateRootView of ember instance and change it to use prependTo. Have a look how Fastboot does this.
Update: This is an instance-initializer to overwrite didCreateRootView.
export function initialize(appInstance) {
appInstance.didCreateRootView = function(view) {
// overwrite didCreateRootView
};
}
export default {
name: 'prepend-to',
initialize
};
ember/glimmer does not provide an prependTo method. You have to implement that one on your own following the implementation of appendTo.
Please also note that didCreateRootView is a private hook. Don't expect that one to keep stable over time.
In general I would not recommend to go this path if there is any other way to achieve your goal. Please consider adding a container for ember at desired position. If you don't have control over HTML markup you might could add a container using jQuery before initializing ember.
Update 2:
import jQuery from 'jquery';
export function initialize(appInstance) {
appInstance.didCreateRootView = function(view) {
let containerId = 'ember-container';
jQuery('<div>').prop('id', containerId).prependTo(jQuery(this.rootElement));
view.appendTo(`#${containerId}`);
};
}
export default {
name: 'prepend-to',
initialize
};
This is not exactly what you've asked for but it's much easier to achieve. If your HTML markup looks like <body><div id="existing-content"></body> and body as default root element above instance initializer will add another div #ember-container before #existing-content and using this one as embers root element.
Update 3:
You find an ember-twiddle here: https://ember-twiddle.com/43cfd1ae978b810f2e7cf445f9a3d40c?openFiles=instance-initializers.root-element.js%2C
If you inspect DOM you will see that ember root element is wrapped by <div id="ember-container"></div>. This wrapper is append to rootElement. So it's before any existing content in rootElement. I guess it's not possible to define a custom index.html in ember-twiddle so I can't demonstrate this one. But you could easily test yourself.

How to remove UI components using React JS

I'm having trouble finding relevant documentation on how to remove UI components when using react. For example, there's a login form. The user clicks submit and now the form should be removed from the screen. How do I do this?
I've found unmountComponentAtNode, but that can only be invoked at the parent level. Am I supposed to have a parent node that is aware of all child state and loads them conditionally? Should all children have an "isHidden" attribute which renders the dom as hidden if true?
This must be basic but I don't see this in the react js tutorials. I found this stackoverflow post (react.js: removing a component) is this really the pattern? It kind of makes sense but it means that a large app will likely have an extremely complex Application parent class that manages maps of application state based on configuration.
It seems like i need to start defining application state as named maps. For example:
BaseApp: showHeader=true;showContent=true;
LoginState: showBaseApp=true;showLoginForm=true;
LoggedInState: showBaseApp=true;showFeed=true;
At any moment we would have to update all state maps and call the base class render method...
In my opinion your question isn't about removing component but about showing the right component. And yes - it can be done with a component state but with Flux/Redux store/reducer as well.
In your example with a login form after click on "Submit" we can change local state for the component and show another text like "The request was sent blah-blah-blah" or another component.
But you can do this by extracting component's local state to a store/reducer and it'll be work better in relatively big app. Nevertheless, it's really up to you where you want to store state.
I like to use a hide prop like so.
class AppCtrlRender extends React.Component {
render() {
let page = this.state.appState.currentPage;
let hideAbout = (page != 'about');
let hideHome = (page != 'home');
return (
<div id='AppCtrlSty' style={AppCtrlSty}>
<div id='allPageSty' style={allPageSty}>
<AboutPage hide={hideAbout} />
<HomePage hide={hideHome} />
</div>
</div>
);
}
}
export default class AboutPage extends React.Component {
render() {
if (this.props.hide) return null;
let aTime = (new Cache()).time.toString();
return (
<div style={AboutPageSty}>
React 0.14 ReFlux used for app state. This is the About Page.
<NavMenu /><br/><br/>
{aTime}
</div>
);
}
}

Categories

Resources