Get HTML in JSON to render as HTML in React Component - javascript

Trying to figure out how can i get the link to actually render as a link. Right now after i read this line of text from my Json file, react renders the hyperlink as literal text, it doesn't render it as a link.
someData.json
[{
"about": "John has a blog you can read here."
}]
someComponent.js
const Person = Component({
store: Store('/companies'),
render(){
var company = this.store.value()[this.props.companyId];
return (
<div id='ft-interviewee className="all-100"'>
<p className="section-heading bold padding-top-20 font-22">Person</p>
<div className="column-group horizontal-gutters">
<div className="all-10">
<div>{company.people.person.about}</div>
</div>
</div>
)
}
});

You can use dangerouslySetInnerHTML
<div dangerouslySetInnerHTML={ { __html: company.people.person.about } }></div>
Example

Another option and I think cheap to use is NPM React Plugin
https://www.npmjs.com/package/react-html-parser
I have used this and feeling good.

Related

is there a way to modify the contents of an HTML tag that is inside a Vue component?

I'm new to Vue.js and haven't yet understood it.
So I was wondering if there is a way in which I can make my custom Vue component(UnorderedList) manipulate the content that is inside my custom component(UnorderedList)
if I have some <p> tags inside my component like this :
<UnorderedList :dashed="true">
<p>some sentence here</p>
<p>some sentence here</p>
</UnorderedList>
then this is what it would look like when the page renders
some sentence here
some sentence here
What I want my component here to do, is add a "-" before every <p> tag, so that when the page renders it should look like this :
- some sentence here
- some sentence here
This is my UnorderedList.vue right now
<template>
<ul >
<span v-if="dashed">-</span>
</ul>
</template>
<script>
export default {
name: 'UnorderedList',
props: {
dashed: {
type: Boolean,
default: false,
},
},
}
</script>
This above code obviously doesn't work the way I want it to.
So, basically I want to add a "-" before everything that is inside the custom component (UnorderedList).
How can I do this ?
I apologize in advance if this is a silly question
you can use vue Filters
Vue.filter('dash', function (value) {
if (!value) return ''
value = `- ${value}`;
return value;
})
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
<div id="app">
{{message | dash}}
</div>
after you created filter you can use it in html template like above (message | dash )

Vanilla JavaScript to React Class/Component

I am new to react and this is my first site and I have some plan JavaScript I found online that will allow a word to be typed out and updated over a course of time. I have already made it into a react Component. But I am not sure how to covert this JavaScript Function into react code.
Here is my new React Component.
import React, {Component} from 'react';
class Hero extends Component {
render () {
return (
<div>
<section id="hero" className="d-flex flex-column justify-content-center align-items-center">
<div className="hero-container" data-aos="fade-in">
<h1>Augusto J. Rodriguez</h1>
<p>I'm a <span className="typed" data-typed-items="opption1, opption2, opption3, opption4"></span></p>
</div>
</section>
</div>
);
}
}
export default Hero;
Here is the vanilla JavaScript that I want to use in my code. Currently this is living in my main.js file that is being called from the index.html. this is the only part of the code that is not working.
if ($('.typed').length) {
var typed_strings = $('.typed').data('typed-items');
typed_strings = typed_strings.split(',')
new Typed('.typed', {
strings: typed_strings,
loop: true,
typeSpeed: 100,
backSpeed: 50,
backDelay: 2000
});
}
I am assuming I need to create a function where my tag is. But I am not sure how to do that in React.
any article references would be awesome or tips on how to resolve this. I have the full code for this project on GitHub.
Looks like that piece of code is using a library called Typed.js.
From looking at your project, I see you setup the Typed.js library inside your public/assets/vendor folder. Instead I would recommend using the NPM package manager to install and setup Typed.js, and copy over the code to work the React way. https://github.com/mattboldt/typed.js/.
Here's an example using Typed.js with React. https://jsfiddle.net/mattboldt/ovat9jmp/
class TypedReactDemo extends React.Component {
componentDidMount() {
// If you want to pass more options as props, simply add
// your desired props to this destructuring assignment.
const { strings } = this.props;
// You can pass other options here, such as typing speed, back speed, etc.
const options = {
strings: strings,
typeSpeed: 50,
backSpeed: 50
};
// this.el refers to the <span> in the render() method
this.typed = new Typed(this.el, options);
}
componentWillUnmount() {
// Make sure to destroy Typed instance on unmounting
// to prevent memory leaks
this.typed.destroy();
}
render() {
return (
<div className="wrap">
<h1>Typed.js</h1>
<div className="type-wrap">
<span
style={{ whiteSpace: 'pre' }}
ref={(el) => { this.el = el; }}
/>
</div>
<button onClick={() => this.typed.toggle()}>Toggle</button>
<button onClick={() => this.typed.start()}>Start</button>
<button onClick={() => this.typed.stop()}>Stop</button>
<button onClick={() => this.typed.reset()}>Reset</button>
<button onClick={() => this.typed.destroy()}>Destroy</button>
</div>
);
}
}
ReactDOM.render(
<TypedReactDemo
strings={[
'Some <i>strings</i> are slanted',
'Some <strong>strings</strong> are bold',
'HTML characters × ©'
]}
/>,
document.getElementById('react-root')
);
It looks like currently you're using the 'typed' library to create this typed list. There are some community packages that act as React wrappers for that, like this one:
https://www.npmjs.com/package/react-typed
Alternatively, you could do what that library does yourself, by loading the 'typed' package in a call to componentDidMount, passing in a React ref instead of a DOM element.
By the way, currently your code uses jQuery (assigned to the variable $) so it's not quite vanilla JS. You could replace the calls to $ with calls to document.querySelector, to make this vanilla JS (though your code might depend on jQuery elsewhere)

Return Vue Component in a custom rendering function for a contentful embedded entry

I'm playing with Contentful! and I'm having trouble with Rich text content field.
I'm using '#contentful/rich-text-types' and #contentful/rich-text-html-renderer modules to customize the way this block is rendered and to display some assets and reference linked in Rich text content.
After calling getEntries in nuxt asyncData function, I've a description data available in my page component.
I'm using documentToHtmlString function with options.
Everything is working fine, but I would like to use a component I have already written (Post.vue), instead of returning the template in ES6 Template Strings.
I know that is possible, but I'm quite new to JS world.
I've tried to require components/post/Post.vue, but I don't know how to use it.
import { BLOCKS } from '#contentful/rich-text-types';
import { documentToHtmlString } from "#contentful/rich-text-html-renderer"
Vue component template where rich text field is rendered
<section class="container">
<div class="columns">
<div class="column">
<div v-html="formatContent(description)" />
</div>
</div>
</section>
I simply call formatContent method to call documentToHtmlString as follow (it works):
methods: {
formatContent(content) {
return documentToHtmlString(content, options)
}
}
And customize documentToHtmlString with options as described in doc:
const embeddedEntryRender = (node) => {
const { data: { target: entry} } = node
const fields = entry.fields
const sys = entry.sys
// LOOK HERE
// const postComponent = require('~/components/post/Post')
return `
<div class="column is-4">
<div class="card">
<div class="card-content">
<div class="media">
<div class="media-content">
<h3 class="title is-4">${fields.title}</h3>
<div class="subtitle is-6">${fields.description}</div>
</div>
</div>
<div class="content">
</div>
</div>
</div>
</div> `
}
const options = {
renderNode: {
[BLOCKS.EMBEDDED_ENTRY]: (node) => embeddedEntryRender(node),
// [BLOCKS.EMBEDDED_ASSET]: (node) => `<custom-component>${customComponentRenderer(node)}</custom-component>`
}
}
No errors detected
--
Thanks a lot
yep you can have a custom vue component in there with a different npm library, I had this same problem.
npm i contentful-rich-text-vue-renderer
in template:
<rich-text-renderer :document="document" :nodeRenderers="renderNode" />
where 'document' is the data sent form contentful, looks like your calling it description. RenderNode is a method described below.
in script:
data () {
return {
renderNode: [INLINES.ASSET_HYPERLINK]: (node, key, h) => {
return h('my-vue-component', { key: hey, props: { myProp: 'blah blah' }},'what I want inside the <my-vue-component> tag'`)
}
}
this might be kind of confusing. So First imprt the richTextRenderer component from that npm library and make sure to declare it in the components section of your vue component. (or gloablly)
Next pass into its 'document' prop the contentful rich text field
if you want custom rendering, pass into the nodeRenders prop a function (I had to declare it in the data section)
My example takes any asset hyperlink type and replaces it with a component of what I want inside the tag
I only got this to work if I globally declared the my-vue-component in the main.js file.
import MyVueComponent from 'wherever/it/is';
Vue.component('my-vue-component', MyVueComponent);
there are more configurations for this, just read the npm libs documentation (though its not great docs, it took my a long time to figure out how to pass props down, I had to read their github code to figure that out lol)

Cannot load data.json file using jQuery and React.js

I must say first that I come from mobile development. I am very new with web development so this is probably an amateur questions.
I am building a react.js project using create-react-app (which uses Babel). I am trying to follow a tutorial where I am supposed to import a *.json file when my component mounts. I can't seem to be able to access my data, and I get an error saying "filteredApts.map is not a function".
Here are my imports:
import React from 'react';
import './App.css';
import $ from 'jquery';
Here is my componentWillMount method:
componentDidMount: function() {
console.log($.get('./data.json', function(){}.bind(this))) //This seems to get an HTML Page returned!
this.serverRequest = $.get('./data.json', function(result) {
var tempApts = result;
this.setState({
myAppointments: tempApts
}); //setState
}.bind(this));
},
my render method:
render: function() {
var filteredApts = this.state.myAppointments;
filteredApts = filteredApts.map(function(item, index) {
return (<li className="pet-item media" key={index}>
<div className="pet-info media-body">
<div className="pet-head">
<span className="pet-name">{this.state.myAppointments[index].petName}</span>
<span className="apt-date pull right">{this.state.myAppointments[index].petName}</span>
</div>
<div className="owner-name"><span className="label-item">Owner:</span>
{this.state.myAppointments[index].ownerName}</div>
<div className="apt-notes">
{this.state.myAppointments[index].aptNotes}</div>
</div>
</li>)
}.bind(this));
return (<div className="interface">
<div className="item-list media-list">
<ul className="item-list media-list"></ul>
</div>
</div>)
} //render
}); //MainInterface
Here is my map of files:
And finally my console log:
Is somebody capable of pointing out what I might be doing wrong?
I'd suggest to change this line:
var filteredApts = this.state.myAppointments;
to this
var filteredApts = this.state.myAppointments || [];
You use asynchronous data fetching and at the moment of rendering it can be no myAppointments yet.
Looks like your responseText is html.
I figured it out.
First, './data.json' was pointing to the public folder by default.
Second, I was missing {filteredApts} in
return (<div className="interface">
<ul className="item-list media-list">{filteredApts}</ul>
</div>)
Thanks anyways to all.

I can't get the html output from draft-js?

I've been playing around with draft-js by Facebook, but I can't actually figure out how to get the html output of the editor. The console.log in the following example outputs some _map properties, but they don't seem to contain my actual content?
class ContentContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
value: '',
editorState: EditorState.createEmpty()
};
this.onChange = (editorState) => this.setState({editorState});
this.createContent = this.createContent.bind(this);
}
createContent() {
console.log(this.state.editorState.getCurrentContent());
}
render() {
const {editorState} = this.state;
const { content } = this.props;
return (
<Template>
<br /><br /><br />
<ContentList content={content} />
<div className="content__editor">
<Editor editorState={editorState} onChange={this.onChange} ref="content"/>
</div>
<FormButton text="Create" onClick={this.createContent.bind(this)} />
</Template>
);
}
}
There is a handy library I used, draft-js-export-html. Import the library and you should be able to see HTML once you invoke the function, stateToHTML:
console.log(stateToHTML(this.state.editorState.getCurrentContent()));
I'm pretty new to React so hopefully this works for you. I looked under the hood of contentState and there is a fair bit going on there that makes using a library to parse out the entities that much more enticing.
The author, sstur, answers a tangentially-related question where I learned about his libraries.
Ewan. I am also playing with Draft.js and came across the same problem. Actually, Victor has provided a great solution.
Here are two libraries that I found. The one mentioned by Victor has more stars on GitHub.
https://github.com/sstur/draft-js-export-html
https://github.com/rkpasia/draft-js-exporter
I just want to add that there is a way to print out the content (in JSON format) without using an external library. It is documented under the Data Conversion session.
Here is how I print out user input using the "convertToRaw" function
console.log(convertToRaw(yourEditorContentState.getCurrentContent()));
Make sure you imported the convertToRaw function from Draft.js by writing:
import { convertFromRaw, convertToRaw } from 'draft-js';
Here is a great blog written by rajaraodv named How Draft.js Represents Rich Text Data. It explained data conversion in detail.
There is readonly attribute to generate just HTML:
<Editor editorState={editorState} readOnly/>
If not willing to add another library to your code, #farincz's approach can work well.
<Editor editorState={this.state.editorState} readOnly/>
The editor state can be directly stored in your storage layer and when you are rendering it to the DOM it is easily available and can help in editing.
By clicking on the text you can make it editable, or bind that click with an edit button. You cannot directly bind click to 'Editor' component, but you can have it on the wrapper containing the 'Editor'.
<div className="editor" onClick={this.editContent.bind(this)}>
<Editor
editorState={this.state.editorState}
onChange={this.onChange}
handleKeyCommand={this.handleKeyCommand}
readOnly={this.state.edit}
/>
</div>
Just add 'edit' to your state as true, making sure that readOnly is true (you can make the name 'edit' of the state more obvious, if it is confusing).
this.state = {
editorState: EditorState.createEmpty(),
edit: true
};
Finally change the value of 'edit' to false on click
editContent() {
this.setState({
edit: false
})
}
To expand on the libraries shared above, here's another good one : draftjs-to-html
It converts raw editor state (JSON object) into plain HTML.
import draftToHtml from 'draftjs-to-html';
import {convertToRaw} from "draft-js";
const rawContentState = convertToRaw(editorState.getCurrentContent());
const markup = draftToHtml(rawContentState);
The most suitable package to convert to HTML and from HTML is draft-convert
However, you should be aware to use the Advanced usage to be able to convert links and to customize the convert process:
const htmlResult = convertToHTML({
entityToHTML: (entity, originalText) => {
if (entity.type === 'LINK') {
return <a href={entity.data.url}>{originalText}</a>;
}
return originalText;
}
})(editorState.getCurrentContent());
const contentState = convertFromHTML({
htmlToEntity: (nodeName, node, createEntity): any | void => {
if (nodeName === 'a') {
return createEntity(
'LINK',
'MUTABLE',
{url: node.href}
)
}
}
})(htmlInput);

Categories