How to get Vue app container div attribute - javascript

I have a page which is being generated by my app in java (SSR) depending on some data (e.g. a publisher for some entity). I would like to create some sort of a reusable Vue component that would call an API method and request some data about the entity that is currently opened. Also in some cases there could be more than one such component on one page.
The only thing I cannot really figure out being a most-of-the-time backend developer - is how to tell a component which entity I'm trying to get. The only solution that comes to my mind is to generate the parent <div class="my-vue-component"><div> with an additional attribute, e.g. <div class="my-vue-component" publisher-id="123"><div>.
But I cannot find if there is a way to access that attribute from inside the Vue instance. (Please note that I don't have a fixed id for this div as there can be many such components on the same page referring to different data).
Any kind of advice is appreciated.

As stated in the previous answer, you will need to use props. Although since you will pass down data to multiple components and the data can change, there should be a way to respond to those changes.
For that, you will have to bind the prop with a reactive variable in your page/parent component.
So your SSR code should look like
<my-vue-component :publisher-id="openId"></blog-post>
And inside your page/parent component will reside the openId, which you can change as needed, and your component will re-render if prop passed to it changes.
export default {
data(){
return {
openId:1
}
}
}

It seems like you are looking for components-props.
You can define a prop like
Vue.component('blog-post', {
// camelCase in JavaScript
props: ['postTitle'],
Your SSR code should then be generating:
<!-- kebab-case in HTML -->
<blog-post post-title="hello!"></blog-post>
Inside the component methods you can access the passed in value using this.postTitle

Related

How call a method from an other component

I have made an example in Codesandbox
Is there a way to collapse the sidebar by clicking on the button 'Col-2'. The button 'Col-1' is working fine, but it's necessary that is works by clicking on 'Col-2'.
I've tried to call the collapsedButton but this didn't work.
<script>
export default {
name: 'template',
methods: {
setCollapsed () {
this.collapsed = !this.collapsed
},
collapseButton () {
this.$emit('setCollapsed')
this.collapsed = !this.collapsed
}
}
}
</script>
Can someone help me out with this?
You should make collapsed a prop and control it from the parent component. You'll need to listen for the event (this.$emit('setCollapsed')) in the parent component and update collapsed accordingly.
I hope this helps, good luck!
The recommended way to achieve this is to use a store.
The store is a module, external to any component, which can be imported in any number of components. When the state of the store (which is pretty much like the data function of a component) is changed, the change is propagated in every single component where the store is used.
Since you're using Vue 2, you could use a mixin.
Here's a mixin using a basic version of a store, under the hood: https://codesandbox.io/s/vue-forked-tz1yox?file=/src/components/sidebar.vue
In more detail, it uses a reactive object which serves as shared state for sidebar's collapsed status while exposing a writable computed (collapsed) and a toggleSidebar method.
Using the mixin in any component is the equivalent of writing the writable computed and the method into the component.
Note: mixins don't play nice with TypeScript. But the above solution doesn't need a mixin. I only used one so I didn't have to write the same computed and same method in both components.
The key to it working is the shared/external reactive object. In Vue 3 you would achieve this using Composition API.

Is it good practice to pass component instance as props to another component in VueJs?

Assume that we are going to make a text edior.
When typing, Component C(Text input section) needs the state of Component B(Font stlye picker) to determine what style to use.
We can share that state by Vuex, but in OOP, related logic or variables are better to be put in same class, and when other components need the state of that object, just to refer it directly.
If I want to refer components directly, one way is to save some components when they are mounted, and pass them as props to other components as the following.
// in <template>
<FontStylePickerVue ref="stylePicker" />
<TextInputSectionVue
ref="textInputSection"
v-bind="{
tylePickerComp: stylePickerComp
}" />
//in Main Component <script>
mounted(){
this.tylePickerComp = this.$refs.stylePicker;
}
data(){
return { tylePickerComp : null }
}
In Vue, although there are many ways to communicate between components, I never seen any of them passes component instance as props directly like this.
(it works, and very convinient though.)
I know doing like this, in a way, it make system more complicated because components refer each others in a complex relation, but I'm just wondering if there is any design pattern like this in Vue, or doing like this has some cons like low perfermance ,etc.
In the end, in order to clarify the idea, I want to compare what if I pass component as props directly or use common methods in this example:
Pass component as props directly:
Need to save component reference on mounted, but type declartion is once and for all(ex. use InstanceType). Need to deal with null(it's null before mounted).
Event bus:
Emit an event with a promise resolve function as callback to make other components to resovle with their state. This is good because it will keep data or logic in the same class(compare to use Vuex), but you need to write your method in a promise style in order to read resolved result.
Vuex:
Split some variables into global scope, and this is not so compatible for cases which are better to gather logic and data at same place.
Just want to get some idea for this topic, sorry for long article.

How to pass data fetched from http, from a Mat-Dialog Component to a Parent component in angular 6?

Actually I have a component typescript file having two classes one for normal component and another one for mat-dialog,
I got the data from http, but I want to pass to parent component.
I want to send the results of this.api.filterHotels(this.filterForm.value); to parent component , How? since Iam not using <Mob-filter-dialog> tag anywhere in html file.
Mat Dialog has a specific usage and do not work with HTML tags.
Use the provided injector. You can pass data through the dialog.close() method that takes one argument. Then use the afterClosed observable to fetch that data.
Here is a piece of the mat-dialog official doc:
dialogRef.afterClosed().subscribe(result => {
console.log(`Dialog result: ${result}`); // Pizza!
});
dialogRef.close('Pizza!');
Good luck, it's not an easy one to get at first, but the documentation explains it well

How can a parent component communicate with a child component in Vue.js?

This is what I have:
<div id='vnav-container'>
<input type="text" v-model="searchTerm" v-on:keyup="search" class="vnav-input">
<menu :items="menu"></menu>
</div>
The outer component contains a search-input and a menu component.
When the user performs a search on the outer component, I need to call a method on the menu component, or emit an event, or whatever, as long as I can communicate to the menu component saying it should filter itself based on the new criteria.
I've read somewhere that calling methods on child components is discouraged and that I should use events. I'm looking at the docs right now, but I can only see an example of a child talking to a parent, not the other way around.
How can I communicate to the menu component as the search criteria changes?
EDIT
According to some blog posts, there used to be a $broadcast method intended to talk to child components but the documentation about that just vanished. This used to be the URL: http://vuejs.org/api/#vm-broadcast
The convention is "props down, events up". Data flows from parents to child components via props, so you could add a prop to the menu, maybe:
<menu :items="menu" :searchTerm="searchTerm"></menu>
The filtering system (I'm guessing it's a computed?) would be based on searchTerm, and would update whenever it changed.
When a system of components becomes large, passing the data through many layers of components can be cumbersome, and some sort of central store is generally used.
Yes, $broadcast was deprecated in 2.x. See the Migration guide for some ideas on replacing the functionality (which includes event hubs or Vuex).
Or you can create the kind of simple store for that.
First off, let's create the new file called searchStore.js it would just VanillaJS Object
export default {
searchStore: {
searchTerm: ''
}
}
And then in files where you are using this store you have to import it
import Store from '../storedir/searchStore'
And then in your component, where you want to filter data, you should, create new data object
data() {
return {
shared: Store.searchStore
}
}
About methods - you could put method in your store, like this
doFilter(param) {
// Do some logic here
}
And then again in your component, you can call it like this
methods: {
search() {
Store.doFilter(param)
}
}
And you are right $broadcast and $dispatch are deprecated in VueJS 2.0

How to use custom functions in a React class after it was rendered?

Let's say that I create additional functions in my React components, something like this:
class Cart extends React.Component {
render() {
return <div id="cart">My Cart Items</div>
}
getItem(id) {
// magically return the item
}
addItem(id, name, type, price){
// you get the idea
}
}
Now, what is the best way to access getItem function from outside the class? For example, something that can be used as window.Cart.getItem. It seems to me that these functions are part of the prototype (non-initialized) of nodeName property of what ReactDOM.render returns.
What is the correct way for this? Thanks.
That's not really how react is supposed to be used.
What you are trying to do looks like MVC, and react is a completely different thing.
a React component like your <Cart> receives props from its parent (could be the root reactDOM.render() or another react component)
a React component may have internal and private method to retrieve additional data from elsewhere (but NOT from other react components)
with these inputs (and only these inputs), the component knows what and how to render itself and possibly also children components to the DOM
the stuff the component (or its children components) render may include interaction handlers (e.g. remove from cart button like `
these interactions could fire an internal method inside the component
and the internal method could call a method in a parent component, if it was passed down as a prop.
or call some remote function to remove item from cart on server side.
In react terms, the <Cart> component is not the owner of the cart contents. It gets them as props, or retrieves them from somewhere else.
React really wants you to ONLY update the cart by passing a new set of props to the component to render.
You could try to shortcut react design by trying to expose any methods from the component to the outside world, but this goes against react design principles.
React has a one way data flow: a component gets props, and renders.
For reference, I can recommend this page on react principles.
You can make a reference to the instance :)
<Cart ref={function(instance){ window.CartInstance = instance }} />
window.CartInstance.getItem(foo);
ES6
<Cart ref={(instance)=>window.CartInstance = instance} />
window.CartInstance.getItem(foo);

Categories

Resources