Vue v-if with laravel backend data - javascript

I have an app which uses laravel for backend/api and vue components in views for frontend, this is a nice combo imo.
This is what I do right now:
#if(count($latestPosts) > 0)
<div class="LAYOUTwrapper_section">
<layout-title-2 :title="'Últimas publicaciones'"></layout-title-2>
<post-list-1 :posts="{{ json_encode( $latestPosts ) }}" :title="'Últimas publicaciones'"></post-list-1>
</div>
#endif
Now when I want to check if I should render a component (postsarray may be empty, then not render post component) I use blade conditional syntax, now this works but I'm thinking about moving this logic to vue components, keep blade syntax to minimum and handle this in the frontend with vue entirely.
Now my question is how can I check if a laravel array is empty in vue component placed on blade view file, not inside the component, basically I want to use v-if to check if $posts ilength is more than 0 inside v-if
Bellow code doent't work but I'd like something similar.
<div class="LAYOUTwrapper_section" v-if="{{ json_encode($latestPosts).length > 0 }}>
<layout-title-2 :title="'Últimas publicaciones'"></layout-title-2>
<post-list-1 :posts="{{ json_encode( $latestPosts ) }}" :title="'Últimas publicaciones'"></post-list-1>
</div>

You have a few options.
Better Solution
Really decouple your component by moving the data behind an API and have your component request the information it needs from an endpoint. Your App/Wrapper/Component should be responsible of getting the data it needs.
Not so great solution
v-if expects a Javascript conditional, so you could just get your blade to render the HTML template as v-if="true" or v-if="false", Note that if you mistakenly pass "false" instead of false, Javascript will interpret this as a truthy value, and the logic will break.
When vue takes over and renders the component, the boolean should kick in on mounted.
You can also pass the value as a prop to your component.
<layout-wrapper :shouldDisplay="{{..}}" /> and use that on the v-if.
{
template: `
<section/>
<div class="LAYOUTwrapper_section" v-if="shouldDisplay"></div>
</section>
`,
props: {
shouldDisplay: Boolean
}
}

Related

what can't be passed by vue slot props?

In official react docs, It says the difference between 'other libraries's slot' and 'react's props.children' is as follows :
This approach may remind you of “slots” in other libraries but there are no limitations on what you can pass as props in React.
https://reactjs.org/docs/composition-vs-inheritance.html
And it sounds like there are some things can't pass through a 'vue slot'. Is there any thing can't be passed by vue slot's props?
In vue you have props as well. The difference and what may have been confusing you is that:
(vue) props === (react) props
(vue) slots === (react) props.children
You can pass data through props in both frameworks/libraries, but what you place inside <YourComponent>[content]</YourComponent will in vue terms be a slot and in react terms be accessible through props.children.
Let's say we have a popup/modal component which sole purpose is to act as a frame for the actual popup/modal content:
// parent component
<Modal>
<p>Watch out! Do you want to continue</p>
<button>Yes</button>
<button>No</button>
</Modal>
Then you would have the modalcomponent itself
// react
<div>
// this will output whatever you put inside the
// <Modal> tags in you parent component
{props.childen}
</div>
// vue
<div>
// the <slot> tag works the same way
// as React's {props.children}
<slot></slot>
</div>
Read more about vue slots here and vue props here.
When you're more familiar with the concepts you can read about vue's named slots here

Difference in property binding for custom component in Ember V/s Angular

In Angular, if we want to bind a property from outside for a custom component, we have to use "#Input" to kind of allow that property to be set from outside (i.e. from consuming component template)
Does EmberJS also have some sort of similar mechanism OR does it allow binding directly from the template (hbs) without adding/marking anything in the component JS? Is there any difference when it comes to Ember Octane V/s the earlier versions of Ember?
yes it allows binding from outside the component without adding anything to the component js
in the component hbs file
<p>{{#attribute}}</p>
from outside
<MyComponent #attribute="attributeValue"/>
also you can get the binded attribute from component js
#tracked mycomponentAttribute = this.args.attribute;
in the component hbs file
<p>{{this.mycomponentAttribute}}</p>
no you don't necessarily have to add the input tag but you have to declare the property inside the component you are trying to pass the property to.
{{#each model as |post|}}
{{blog-post title=post.title body=post.body}}
{{/each}}
the blog-post component, define a property named title and this should work.

With VueJS Cli how should do to have a variable common to all pages and be able to watch it in a page

I'm relatively new to VueJs and I'm stuck on a project and I can't find a solution online.
I want to have a variable commun to all pages (month), and when that variable change I want to be able to do something on my page.
Example of what I want to do (simplified)
In App.vue
<div id="app">
<div id="topBar">
<div id="nav">
<div><router-link to="/">Home</router-link></div>
<div><router-link to="/expenses">Dépenses</router-link></div>
<div><router-link to="/revenues">Revenus</router-link></div>
<div><router-link to="/category">Categories</router-link></div>
</div>
</div>
<select name="selectMonth" v-model="month" id="selectMonth" required>
<option v-for="(month, index) in months" :key="index" :value=month>{{ month }}</option>
</select>
<router-view/>
</div>
In Home.vue or any other page
watch: {
month: function () {
this.getExpenses() // or something else (In this case I want to fetch data again with a new month)
}
},
But since the variable is changed on the app.vue, (no matter what page I'm on) I can't watch it on my page.
Do you know how I should do? What is the best practice for that kind of stuff?
Thanks in advance if someone can help me!
EDIT: SOLVED
State Management and $emit did the trick. While discovering Vuex I found out that my app didn't need such a big state manager so I've found another way (based on the same idea):
I've created a bus.js with an empty Vue instance:
import Vue from 'vue'
const bus = new Vue()
export default bus
Then in my component I use
import bus from '../bus'
...
onChangeMonth () {
bus.$emit('new-month', this.month)
},
And on my pages :
import bus from '../bus'
...
created () {
bus.$on('new-month', this.getExpenses)
},
Component based UI frameworks like Vue, React, and friends enforce the idea of passing data down into components (Props in Vue) but not allowing those components to pass updates to that data up to parents by simply changing the data. The reason for this is performance; making data changes explicitly allows the framework to only re-render when it needs to.
Instead of updating props that have been passed into a component, updates can be passed up with events or by using a state manager like Vuex.
If you're looking for a simple way to achieve this, check out $.emit : https://v2.vuejs.org/v2/api/#vm-emit

Vue.js - component inside component

I do have my component called Grid. Inside this component I load JSON data from server and i render them. They are mostly string and integers. Sometimes the JSON contains HTML like <strong>myvalue</stong> so I render the data with three brackets {{{ and }}}.
The thing is when the HTML is not pure HTML but component like <my-component my-param="1"></my-component>. How to tell to Vue.js to render this coponent? All I get is the HTML purely printed into grid.
Thanks
You need to compile again that piece of code you've loaded from remote.
ps: I will use jQuery to manipulate the DOM.
Inside this component I load JSON data from server and i render them.
I'll assume you have a function named "loadAndRenderFromServer()", please adapt the code below to fits you.
Eg: If your grid has the markup <div id='grid'>
// vuecomponent.js
export default {
[...]
methods: {
loadAndRenderFromServer() {
// first, load remote content and insert into #grid
// now, compile
this.$compile($("#grid").get(0));
}
},
[...]
}
You may need to use "decompile" if your component starts to duplicate the loaded content. Check into VueJS docs for compile and decompile methods.
Using v-html (which is equivalent to {{{}}}) will not render what's inside it if it's a component.
Instead try to use <slot> in your parent template.
Otherwise, if you want dynamic components you need to use <component> and if you want content inside those dynamic component you need to use <slot>s.
I would suggest you to use something like
<component :is="myComponent" />
and inside the models of those components put some <slot>s to insert arbitrary content.

Clientside react-script overrides serverside rendered props

In my serverside react rendering, I pass a property to the JSX:
markup: React.renderToString(Admin({ field1: "Hallo" }))
The JSX looks like this:
<MaterialTextField hintText="field1" floatingLabelText="field1" type="text" name="field1" value={this.props.field1} />
Now, I ned to render the JSX also on clientside for having the event listeners, etc.:
React.render(
<Admin />,
document.getElementById('react-app')
);
The problem is: Because the rendered markups are not the same, the value of the text-field gets lost. How could I fix that?
React will check that any initial markup present matches what's produced for the first render on the client by comparing checksums between the initial client render and a checksum attribute in the server-rendered markup, so you must make the same props available for the initial render on the client in order to reuse the markup.
A common way to do this is to serialise the props to JSON so they can easily be included as a variable in the initial HTML sent to the client:
res.render('react.jade', {
markup: React.renderToString(React.createElement(MyComponent, props)),
props: JSON.stringify(props)
})
...
body
div#app
!= markup
script window.INITIAL_PROPS = !{props}
script(src='/js/app.js')
By passing it as prop to the Admin component just as you pass this.props.field1 to the MaterialTextfield using <Admin field1="Hallo" />

Categories