Linking two Vue.js components - javascript

I have one single file component that is used to show data and another one that is used to edit the same data. The view has labels and paragraphs where as the edit component has inputs and textareas.
Both of these components take the same data object. Is there a way that by editing the fields (bound with v-model in the edit component) the changes a reflected to the view component?
For example, here's my paragraph.vue that is used to show the data
<template>
<div class="row">
<div class="col-xs-12">
<p>{{ text }}</p>
</div>
</div>
</template>
and here's the edit dialog
<template>
<div class="form-group">
<label for="paragaph-text">Paragraph</label>
<textarea id="paragaph-text" class="form-control" v-model.trim="text"></textarea>
</div>
</template>

If you have multiple components using the same data, you can use a share state as explained in the documentation.
But if the number of components increases, and there are many changes happening, you may need a Centralized State Management like vuex, which is generally preferred in due community.

Related

How to render VueJS Slot in a another component

VueJS slot could be placed anywhere inside a parent component.
However, I have a use case where I need to show a slot in another (foreign) component outside the parent component.
For example, I have component Student:
<template>
<slot name="detail" />
<slot name="status" /> <!-- I don't want to render this slot inside this component, but somewhere else -->
</template>
I want to display the student's status in a header section outside the student component as below:
<div class="Header">
<!-- student status slot should go here-->
<student-status-slot></student-status-slot>
</div>
<div class="InputForm">
<student>
<template #detail>This the detail information about student</template>
<template #status>Grade A</template>
</student>
</div>
You may suggest to create a new "student-status-slot" component. However, the idea is to have all student related information, including "status" declared under the component, but render some of the slot somewhere else.
I have tried another approach creating a separate component and pass the status data via prop. But That is not what I wanted to achieve. I don't want to pass data, but re-use the student status component, which can be dynamic.
In a parent component you can access child's slots by adding ref attribute to child, and then render the VNode obtained. See the demo here https://codesandbox.io/s/happy-einstein-9f5rke?file=/src/components/StudentPage.vue
But actually I wouldn't recommend this way such it's not conventional and slots were not designed for this. I think you should rather consider using portals (Vue 3 portals or https://www.npmjs.com/package/portal-vue if you use Vue 2) to achieve your goal

How do I slice *ngFor in a component based on the components it is injected into?

The following code is a component that i need to inject in other components:
<div class="row">
<div class="col-12 [...]" *ngFor="let course of courses">
<div class="card">
[...]
</div>
</div>
</div>
The problem is that in one of the components it is injected in, I need to apply a | slice:0:4 in the ngFor to display less data. For this reason, I modified the child component and made it so the data from the parent components is sent to the child component. So I removed the .row and .col-12 divs and put it into the parent components, this way I can use the slice only in the parent component I need to.
<div class="row">
<div class="col-12 [...]" *ngFor="let course of courses | slice:0:4">
<app-child-component [course]="course"></app-child-component>
</div>
</div>
Child component now is like this:
<div class="card">
[...]
</div>
The problem now is that I need to apply CSS classes to the child component's .row that must be visible everywhere but this way I have to modify every single parent component's .row, so more useless code. I also assume this way I'm not using Angular's components concept the way it is meant to.
Is there a way to use | slice and kind of "send it" from a single parent component to the child component like i'm doing now with [corso]="corso" in <app-component [corso]="corso"></app-component>?
Hoping I explained this well. Thank you.
//Child component ts
#Input() sliceStart = 0; //default to `0` if not passed
#Input() sliceEnd = 4; //default to `4` if not passed
courses = ['HTML', 'CSS', 'Javascript', 'Angular'];
<!-- Child component html -->
<div *ngFor="let course of courses | slice: sliceStart:sliceEnd">
{{course}}
</div>
<!-- Parent component html -->
<app-child-component [sliceEnd]="2"></app-child-component>
Stacblitz example

Is it necessary to use Vuex for a Vue-based shopping cart?

I want to let two separate Vue components communicate with each other (not siblings, so not child or parent).
Let's assume I have a Laravel blade template file like that:
<div id="app">
<div class="header">
<shopping-cart></shopping-cart>
</div>
<div class="content">
<products-list></products-list>
</div>
</div>
How can I send a product from component to component (putting products to the cart) ?
If you want to get the right solution with the right structure, and it's simple, you have to use the State Manager(Vuex), because it's the best solution.
I wanted to write this in the comment, but I could not because I did not have enough reputation.

How to create a custom refinement list in vue instant search?

I am working with Laravel Scout and alogolia as the driver. Since I have vue on the front end, I tried the vue instant search package which works really well.
The issue that I am facing is that I need to customize it to the in app styles we are using.
Refinement Section
This is the particular component I am trying to customize. It tried over riding the classes like they show in Styling Section but that won't cut it for me since I need to add more tags and attributes in there.
<ais-refinement-list attribute-name="categories.title" inline-template>
<div class="column w-1/5">
Hello
</div>
</ais-refinement-list>
Now I know I can start to write an inline template like so but what I don't understand yet, is how to get the values for refinements so I can make the checkboxes and furthermore how to send them back to the component once they are selected. Any help is appreciated.
I dug through the package it self here and then found the template inside here. For some reason I could not see this in vendor code.
Got all the variables and method calls from in there
This is the custom version:
<ais-refinement-list attribute-name="categories.title" inline-template>
<div class="column w-1/5">
<h3>Categories</h3>
<hr class="my-3">
<div class='column w-full mb-4' v-for="facet in facetValues">
<div class="checkbox-control mb-4">
<input type="checkbox" :id="facet.name" :value="facet.name" v-model="facet.isRefined" #change="toggleRefinement(facet)"/>
<label :for="facet.name">{{ facet.name }} ({{ facet.count }})</label>
</div>
</div>
</div>
</ais-refinement-list>

Knockout nested components

I am trying build components with help of KO component binding, but i have a small problem with nested components.
The scenario is I have text-input component which has a label which also is a component.
<div data-bind="component:{name:'text-input', params:{data:$data, parent:$parent}}," class="form-horizontal">
<div class="form-group row">
<div class="col-sm-1">
<div data-bind="component:{name:'label', params:{}}"></div>
</div>
<div class="col-sm-11">
<input type="text" data-bind="value:value" class="form-control" />
</div>
</div>
</div>
Label component has a JS and a template, template looks like below
<label data-bind="text:labelText"></label>
But I am getting an error Multiple bindings (text and component) are trying to control descendant bindings of the same element
I understand <div class="col-sm-1">element is already bound to text-input context. Now the question is how to achieve this scenario.
The component binding fills the content of the <div> with the component's template, wiping out whatever else might be inside (hence the error). One option would be to add another component binding inside the text-input component's template which would allow a componentName/componentParams to be passed in {componentName: label, componentParams: labelParams}. You could also look at working with component child nodes added in Knockout 3.3.
Actually found the issue. It's kind of silly mistake.
My registered component is label and in my label's template I have <label> HTML tag, but since label is also a component, KO was trying to bind label's template to label tag which resulted in error and recursive loop.

Categories

Resources