I'm having some problems with the convertFromHTML, it doesn't render the right data as I expected.
For example,
_html_: <p>Paragraph 1</p>, <p>Paragraph 2</p>, <p>Paragraph 3</p>
_editorState_:
EditorState.createWithContent(ContentState.createFromBlockArray(convertFromHTML(_html_)), Decorator)
The html at this stage render correctly as expected.
Paragraph 1
Paragraph 2
Paragraph 3
However, when I save data and refresh the page, it displays as below (all in one line)
Paragraph 1 Paragraph 2 Paragraph 3
Then, I clicked on the editor and suddenly the html turned into
<p>Paragraph 1 Paragraph 2 Paragraph 3</p>
Does anyone has similar problem like this? Thanks.
What do you mean, "when I save data"?
@spicyj, sorry for my uncleared explanation.
here is an example,
_html_: <p>A</p><p>B</p><p>C</p>
Basically the result that I've got from convertFromHTML(html) is
Object {key: "1lic8", type: "unstyled", text: "A B C", characterList: Array[5], depth: 0}
I expected to get 3 _ContentBlock_ objects as there are 3 paragraphs.
Object {key: "d1m9h", type: "unstyled", text: "A", characterList: Array[1], depth: 0}
Object {key: "4qnh7", type: "unstyled", text: "B", characterList: Array[1], depth: 0}
Object {key: "457nc", type: "unstyled", text: "C", characterList: Array[1], depth: 0}
Thanks, I can repro this.
@spicyj I can take a look at this this week if no one else is.
@CLowbrow Go for it.
Is there currently a workaround for this?
Workaround: convertFromHTML takes as its optional third argument a "block render map" -- I believe if you specify a map that includes the <p> tag as output then paragraphs will be mapped to that block type.
Thanks @spicyj
I tried applying the workaround but without success. Did you figure out a solution @abhoopathy ?
I passed a render map like that:
const blockRenderMap = Immutable.Map({
'paragraph': {
element: 'p'
},
'unstyled': {
element: 'p'
}
});
Thanks!
Edit: I ended up storing my input content as draftjs raw datas (using convertFromRaw, convertToRaw instead of trying to output/input some HTML). I would advice anyone wanting to save datas from DraftJS to a DB to do so until some improvements are done with the HTML importer/exporter. Also to display content as HTML, I used this HTML exporter: https://github.com/sstur/draft-js-export-html
Same here, couldn't get that render map to work correctly.
tags just kept getting combined.
My workaround was to replace 'p' tags with 'div' tags in my HTML. Obviously this workaround only works if you have access to the input HTML.
OK. Seems <p> tags wont work in DraftJS. Maybe I was doing smth wrong, but it looks DraftJS wraps any text contents into div -> span and then wraps this into whatever element you provide in your blockRenderMap. Since <p> element supports only Phrasing content children it throws violation error since <div> cannot be a child of <p>.

@jbrozena22 I tried same approach, but it only worked in case all blocks were <p />. If there was at least some known block right after <p />, say <h2 /> it combined all <p />'s into one <div /> with text being concatenated. My use case was copy/pasting content from other editor (Medium).
My 'workaround' was to replace all <p> tags with <section>ones (since I have access to input HTML string). And then add section to blockRenderMap
@N1kto this workaround works but has a severe drawback: deleting section element requires two backspace .
there's a function called getBlockMapSupportedTags in convertFromHTMLToContentBlocks.js which join the chunks of two unstyled element, should we remove the filter in this function?
@NdYAG well, haven't even noticed that drawback to be honest. Comparing to initial problem that's a minor issue, at least for me.
Not sure that exactly getBlockMapSupportedTags causes blocks combining, since it only returns a list of supported tags, joinChunks seems to be responsible for that. But removing the filter within getBlockMapSupportedTags should make it possible to map <p /> elements (or any other) to divs within blockRenderMap, e.g.
Draft.DefaultDraftBlockRenderMap.merge(Immutable.Map({
p: {
'element': 'div'
}
}))
However don't know what would be other consequences of doing that - it has been added there for some reason. Also it might be overwritten by default unstyled record - since it also maps to div element.
This worked for me:
import {
DefaultDraftBlockRenderMap,
ContentState,
convertFromHTML,
getSafeBodyFromHTML
} from 'draft-js';
const blockRenderMap = DefaultDraftBlockRenderMap.set('p', { element: 'p' });
const blocksFromHTML = convertFromHTML(html, getSafeBodyFromHTML, blockRenderMap)
.map(block => (block.get('type') === 'p' ? block.set('type', 'unstyled') : block));
const contentState = ContentState.createFromBlockArray(blocksFromHTML);
_edited to show imports_
@davidchang you've closed both this task and #757 (where you said you were closing that one in favor of this one) and there is no consolidated task created (at least not referenced). Is it intentional?
This issue is still open.
@spicyj @davidchang I am sorry, must have overlooked.
@tomconroy Can you tell me please what getSafeBodyFromHTML looks like? Without that, browser shows an error DOMBuilder is not a function
@ZeroCho Maybe you can use a jsdom to do this behavior on the server. Like this:
function getSafeBodyFromHTML(html) {
var doc = jsdom(html);
var window = doc.defaultView;
global.HTMLElement = window.HTMLElement;
global.HTMLAnchorElement = window.HTMLAnchorElement;
return window.document.body;
}
@tomconroy @landrade
Oh oh, never mind. I found out that I can import { getSafeBodyFromHTML } from 'draft-js'.
Thanks for helping me!
I just realised this is particularly problematic when copy-pasting Draft.js images from one editor to another. If the unstyled blocks in-between the images are empty, then they will be removed in the target editor... and it becomes impossible to select the images to remove them or add content before/after.
Edit: this also happens for other empty tags, not just p, so the problem here might be closer to #1082.
Here's an example from my demo site:

In that example, the content changes from unstyled, atomic, unstyled, atomic, unstyled to atomic, atomic which makes it completely impossible to use the editor.
Here is another illustration from Facebook Notes:

If there was a viable workaround for this, out of all place I imagine it would have one.
Most helpful comment
This worked for me:
_edited to show imports_