Vue.js - component inside component - javascript

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.

Related

Vue v-if with laravel backend data

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
}
}

How to create inject React components from XML

Imagine you made a web framework that helps you quickly make blogs for clients. For the sake of this post, its the same blog template everytime, what changes is the content. You're React app is a simple structure of the following [where the Content state is just changing each time]
<App>
<Navigation/>
<Content/>
</App>
What makes the framework is you have XML files which contain the HTML. Each XML file represents one blog post. The app pulls all the HTML from the XML files, and puts it into the state of the App in a "blog posts" array. Depending on the state of the app, a specific entry in the array will be displayed in Content...
Content's state has a field called "html" which is what holds the HTML to be injected in string form. [you have to use dangerouslySetInnerHTML]
This concept works fine, and I have a version of it now. However, imagine you have a React components that you want to add to each blog post. Say you want to add the component into a specific blog post in a specific section. You want to add props to it and such. Now this goes out the window with dangerouslySetInnerHTML
This is where I am stuck trying to find the best direction to go. The only thought I have now is the following:
Since you would now be writing JSX in the XML, just make each blog post its own component. You would have ...etc and then if this.state.currentPost === 1 then display BlogPost1 and likewise. Yet you would have to have a huge block of if-statements depending on how many blogposts you have, and its not ideal to have to add everytime you have a new blogpost
When I read the title of your question I got curious and found this library to parse XML into React components: xml-to-react. But that's not what you are asking for.
As you want to use components in the middle of you string of HTML, I'll suggest: react-remarkable. This component compiles its children (a string with markdown/html/react) into react nodes.
Example from its docs:
var React = require('react');
var Markdown = require('react-remarkable');
var MyComponent = React.createClass({
render() {
return (
<div>
{/* Pass Markdown source to the `source` prop */}
<Markdown source="**Markdown is awesome!**" />
{/* Or pass it as children */}
{/* You can nest React components, too */}
<Markdown>{`
## Reasons React is great
1. Server-side rendering
2. This totally works:
<SomeOtherAmazingComponent />
Pretty neat!
`}</Markdown>
</div>
);
}
});

Vue 2 - render components from an ajax response

Is there a way to render components that come from an ajax response?
For example, I registered a component "Test" and in the ajax response I have:
<p>dummy paragraph</p>
<test></test> <!-- vue component I want to render -->
<p>another dummy paragraph</p>
My final goal is to make a shortcode that lets the user insert a router link in the content area.
I'm using Vue 2, vue router
Edit: here is a demo https://jsfiddle.net/Paulius_Krutkis/4mb1ypqs/
I am not sure, what is the exact issue you are facing here, If you are looking for how to render the HTML returned from ajax call, You can use v-html which can render the string variable having HTML.
However be aware:
Note that the contents are inserted as plain HTML - they will not be compiled as Vue templates.
So v-html will not compile and and render any vue component as you may expect, you may have to find some other solution for it.
Alternet way
However as you are saying, you need a way to render components that come from an ajax response, You can take help of Async-Components, where you define your component as a factory function that asynchronously resolves your component definition.
see the demo here: https://jsfiddle.net/4mb1ypqs/1/
Yes, there is way for doing this. Follow these steps:
Register the component (which will be sent as an ajax response) globally.
import Vue from 'vue'
import Test from './some/folder/Test.vue'
Vue.component('test', Test)
Either add Vue to the window object or export it and import it wherever you need it. Here i will add it to the global window object so that i can easily access it within the browser console.
window.Vue = Vue
When you get the ajax response with the uncompiled DOM element (<test></test>) you can decide if you want to insert it directly to your DOM and compile it afterwards or compile it first and then mount it to the DOM.
Lets say you inserted the component template directly to the DOM like in your example.
Notice the wrapper element.
<p>dummy paragraph</p>
<div id="testapp">
<test></test>
</div>
<p>another dummy paragraph</p>
Create a new Vue instance and tell it where it should mount. Since your test component is already registered globally, vue knows how it looks like and will compile it once it sees it in the DOM. Alternatively, you can also add it here within your "components" property.
new window.Vue({
el: '#testapp',
})
Done!
Info: VueDevtools will not recognize your new compiled component If you have already a root vue instance mounted initially. To make it work you must tell the newly created instance that it belongs to a parent instance:
var vm = new Vue({
el: '#app',
});
new window.Vue({
el: '#testapp',
parent: vm,
});
Notice: The new vue instance will NOT share data with other instances. This approach is only "meaningful" (of course this whole procedure is not recommended) when you have independent components like for example a text-input component, that is only there to send data to the server independently.
Hope it helps someone out there!

Render function in reactjs

Quick question. I'm learning react js.
When we create a component, we provide in the render function the html template of the component to render.
So far I have only seen small components with very small pieces of html, but I was just wondering what happen if we have a component with a huge html template, is there any way to provide the path to a separate html file? Or we are forced to write all the html directly inside the render function? Thanks!
You should always write it in the render function. You're not writing HTML in there, you're writing JSX, which is compiled into Javascript. Something like <div className="test"> is converted into React.createElement("div", {className: 'test'});.
You shouldn't have an issue of size as long as you break down large components into a composition of many smaller components. You can include other components by including them in your render function, like this: <SomeComponent someProp="someVal" />.
You can split your render function to the bunch of good-named methods like a partials in old plain html-templates. It's useful to make complex react-components, because you will remove big unreadable html-part from your code.
For example, here is some pseudo-code described this approach:
class NavBar extends React.Component {
// Render user name and links on profile and logout
renderUser() {
if (!user) return;
return <div>{user.name}</div>;
}
// Render list with nav-bar items if they exists
renderNavBarItems() {
if (!user) return;
return <ul>{this.items.map((i) <li><a href={i.link}>{i.name}</a></li>)}</ul>;
}
render() {
return (<div className="nav-bar">
{this.renderNavBarItems()}
{this.renderUser()}
</div>);
}
}

How to render ReactJS component from outside of JS class it's defined in and/or with dynamic id element name?

If I defined a ReactJS class in say dialog.js:
var divStyle = {
padding: '15px',
paddingBottom: '12px'
};
var Dialog = React.createClass({
render: function() {
return (
<div style={divStyle}>...</div>
);
}
});
In the above I define a class.. but in every example I see there is also the React.renderComponent(<Dialog/>,document.getElementById('someId'));
The problem I have with this is.. if I want to use this component on different pages with different IDs to render it at, or perhaps for several different IDs, I can't hard-code the id in the actual class it's at. I supposed I can pass in the ID in some manner??
But furthermore, I also want to be able to render the component in say a different JS class, one loaded AFTER the loading of this js class. I have an app.js class for my SPA app, that is loaded last. In it, when a user clicks a link, I may want to only render this component at that time. I do realize in the render method I can control in some way whether or not it's actually rendered.. but my thinking is also to not even bothering inserting it into the DOM unless an action occurs. Sort of like lazy insertion I guess?
I've tried in my app.js:
function () {
React.renderComponent(<Dialog/>,...);
}
but obviously this doesn't work as this JS is not a JSX JS file. So I tried using React.renderComponent(Dialog,...); thinking the Dialog class is globally defined, so it would be available, but that too fails.
So how do I use the Dialog class in another function to render it?
I think you're getting something conceptually wrong here:
but in every example I see there is also the React.renderComponent(<Dialog/>,document.getElementById('someId'));
The fact that the short examples are followed by a renderComponent call is for the trivial reason to show the demos. Once again, keep in mind that in React, <Dialog /> desugars to Dialog(). If you don't call it nothing happens.
So, simply don't call until you need it.
Also, I don't understand what you mean by:
but obviously this doesn't work as this JS is not a JSX JS file
Since you can just process that file through JSX?
If you're having trouble mentally mapping JSX to functions and vice-versa: try the live compiler here: http://facebook.github.io/react/jsx-compiler.html

Categories