get data attribute from “root” DOM node in react js - javascript

Let’s say there is a <div> somewhere in HTML file:
I want to pass an attribute data-person-name from that <div> having id root,to react element
<div id="root" data-person-name="John"></div>
const element = <h1>Hello,{data-person-name}</h1>;
ReactDOM.render(element, document.getElementById('root'));
Please suggest the right way to do that.

A cleaner way would be to prefix all custom attributes with "data-". Because there is no known attribute "personName" for a div element and having that is against W3 rules.
The code may look like this:
<div id="root" data-personName="John"></div>
const element = <h1>Hello,{document.getElementById('root').getAttribute('data-personName')}</h1>;

Related

Is it possible to emulate v-model input behaviour on a paragraph tag?

Solution:
Thanks to #Jeronimas I figured out how to use dynamic components in vue. Basically you create a child component that switches between <p>and <input> tags, depending on props. You have to use <component> element for this, because it's an inherent vue component to manage dynamic components.
child:
<template>
<input v-if="input" type="text" value="hello world">
<p v-else>hello world</p>
</template>
<script setup>
const props = defineProps({
input: Boolean
})
//emit input when form is submitted...
</script>
parent:
<template>
<component :is="p" :input="true"/>
</template>
<script setup>
import p from './p.vue'
</script>
Vue is awesome <3.
Original Question:
Is it possible to input text into <p> tags, so that it will be stored in a database? I want to build a "live" CMS, similar to wordpress/webflow and using formatted <input> fields instead of <p>/<h> elements would make the html messy because, basically you would have to create two identical sites, one with normal text tags and the editable one with input fields, that look like normal text tags.
I was wondering if there is a way to manipulate reactive objects like ref to make it possible?
Alternatively you could create a site completely without normal text tags and instead use input field placeholders but that might mess up SEO.
Like in the comment above using :is could work when switching between the states.
<component :is="tag">
tag value could be dynamic and depending on the tag value the component would change its state.
I would suggest using div with v-html that supports any markup when in live mode and when user is in editing mode display a rich text field. For rich text editing i would suggest to look at https://tiptap.dev/
you can bind the input value and the tiptap would create any html tags you need <p/>, <li/>, <h1/>

Global JS variable to pass HTML chunk to React component

I have a piece of HTML I need to send to a React component on page load without rendering it. I'd rather not us AJAX due to cache, but I may revert to that if I can't figure this out.
On the jsp side, I have this:
<script>window.banner_data_for_desktop = "...droplet..."</script>
This contains the HTML chunk I need to pass
<div id="desktop-top-banner">
<div>
...
</div>
</div>
On the jsx side, I've tried rendering directly like this:
<div id="top_bar">{window.banner_data_for_desktop}</div>
This renders the content, but displays the div tags as a string and not output as HTML.
So then I tried using dangerouslySetInnerHTML like this:
<div id="top_bar">dangerouslySetInnerHTML={{ __html: window.banner_data_for_desktop }}</div>
This results in an error:
Invariant Violation: Objects are not valid as a React child (found: object with keys {__html}). If you meant to render a collection of children, use an array instead.
I've tried using Stringify, toString, creating a function to return the html like this:
function createMarkup() {
return {__html: window.banner_data_for_desktop};
}
All without any luck. If any one has a suggestion to render HTML from the global JS object, I would greatly appreciate it!
dangerouslySetInnerHtml should be an attribute of the tag:
<div dangerouslySetInnerHTML={{__html: "HTML CHUNK"}}></div>

How to remove extra wrapping elements in the rendered HTML?

I started learning angular 5 3 days ago so I'm quite new at it. I also use angularJS and React to develop applications and I think I don't understand how angular 5 components fully work. If I create for example a custom button that has a custom text inside (I'm not saying this should be done this way but it's a simple example that shows my point) like this:
<app-button>
<app-text>
My Text
</app-text>
</app-button>
The rendered DOM results in:
<app-button>
<button>
<app-text>
<span>
My Text
</span>
</app-text>
</button>
</app-button>
which is unreadable, I wanted to know if there's a way to remove this wrapping elements and just place the components layout replacing the tags resulting in the following structure:
<button>
<span>
My Text
</span>
</button>
If there's no way of removing them what are your suggestions? thanks!
Angular components are directives with templates. According to this:
Directive configuration #Directive({ property1: value1, ... })
selector: '.cool-button:not(a)' Specifies a CSS selector that
identifies this directive within a template. Supported selectors
include element, [attribute], .class, and :not().
So component selectors can be also attribute selectors. For your example, instead of writing this:
parent.component.html:
<app-button>
<app-text>
My Text
</app-text>
</app-button>
write this:
parent.component.html:
<button app-button>
<span app-text>My Text</span>
</button>
where :
app-button.component.ts
...
selector: '[app-button]',
template: `<ng-content></ng-content>
...
app-text.component.ts
...
selector: '[app-text]',
template: `<ng-content></ng-content>`
...
this would be rendered as you expected:
Update after your comment about styling those buttons:
To style the buttons from inside the button component, and set class in parent component, use :host-context pseudo-class. It is not deprecated and works well
button.component.css
:host-context(.button-1) {
background: red;
}
:host-context(.button-2) {
background: blue;
}
app.component.html
<button app-button class="button-1">
<span app-text>My Text</span>
</button>
<button app-button class="button-2">
<span app-text>My Text</span>
</button>
Here is the DEMO
I had a similar issue. I'll provide my solution in case someone else has the same problem.
My component should be able to be used either within other components or as a route from <router-outlet></router-outlet>. When I used the selector as an attribute [my-component] things worked perfectly provided it was used within other components. But when created by <router-outlet></router-outlet> a <div> were created automatically.
To avoid that, we can simply use multiple selectors, and consider that the selectors can be combined.
Consider this: I want my component to use the attribute my-component and if it ever should be created by the <router-outlet></router-outlet> it should be wrapped in a <section></section>. To achieve this simply use:
#Component(
selector: 'section[my-component], my-component',
...
)
The result will be, if used inside another tag:
<whatevertag my-component>
... component content ...
</whatertag>
If used as a route:
<section my-component>
... component content ...
</section>

Manipulate dom element outside React component

I have a React component that renders HTML only on a small part of a HTML document.
From within the React component I need to replace an element, that exist outside the component, with a block of HTML.
No matter how much I'm googling this, I cannot find a straight way to accomplish this, I assume that it's because React's guidelines that naturally prescribe to use ref instead.
How would I use document.getElementById() or anything similar to insert the following sample HTML block at the place of a certain div:
<div>
<div class='yellow'>YELLOW</div>
<div class='green'>GREEN</div>
<div class='blue'>BLUE</div>
</div>
Assign an id to the top level element of the html react renders. It will still include the id attribute and thus can still be referenced with document.getElementById
<div id="toReplace">
<div className="yellow">YELLOW</div>
<div className="blue">blue</div>
<div className="red">red</div>
</div>
componentDidMount() { //or wherever
document.getElementById('toReplace').append('more html');
}
const str = "<div><div class='yellow'>YELLOW</div><div class='yellow'>GREEN</div><div class='yellow'>BLUE</div></div>"
document.getElementById('toReplace').innerHTML = "";
document.getElementById('toReplace').insertAdjacentHTML( 'beforeend', str );

Using custom element content as item template

I'm writing reusable components for our internal framework that abstract away some monkey code. Most of the scenario's are implemented with slots and work great. However, some scenario's require rendering templates inside for loops, and unfortunately slots aren't supported there.
I came up with the following (working) code:
<template>
<div class="form-group">
<label for.bind="titleSafe" class="control-label">{title}</label>
<select id.bind="titleSafe" value.bind="value" class="form-control">
<option repeat.for="item of itemsSource" >
<template replaceable part="item-template" containerless>${item}</template>
</option>
</select>
</div>
</template>
This code has, IMO, multiple issues that make it a bad candidate for including it in a framework:
It doesn't support default templates like slots does, so when you have only 1 replacable part the syntax is needlessly verbose
Having to use 2 different templating systems (slots + replace-part) in my project seems really counter intuitive and will certainly create confusion/bugs in my dev team
When you use template parts in the example I provided above, you need to know I declared 'item' as iterator in my for loop in order to construct your template correctly
Therefore I went looking for alternatives. After some research I came up with something like this:
<template>
<div class="form-group">
<label for.bind="titleSafe" class="control-label">{title}</label>
<select id.bind="titleSafe" value.bind="value" class="form-control">
<option repeat.for="item of itemsSource" >
<!-- I want to insert my custom element here -->
</option>
</select>
</div>
<slot></slot>
</template>
The above is my select-item custom element. Then I would also create another custom element for the templating of the repeatable item, like select-item-template, I would then use the two together like this:
<select-item title="myTitle" items-source="myItems">
<select-item-template><span>${myItemsProperty}</span></select-item-template>
</select-item>
The strength of this approach would be that you can create complex 'root' custom elements with one default slot. In this slot, you could then define multiple custom 'child' elements that the root element can search for when it's initialized (I know you can do this with the #child and #children decorators, so that part is covered). I'm a bit lost on how I would have to use these custom child element's content in my root custom element though.. How would I take my span element in the above example and prepare it's content to be rendered in the repeater? And would it be possible to take the repeated item set it as the template's datasource so I don't have to specify itemin my templates?
I hope I didn't make this too verbose, but I wanted to explain what my functional requirement is. If you have any resource that can point me in the right direction I would be very grateful!
Use the processContent attribute to transform the element content into a part replacement. The component will still use replace-part internally but consumers of the component won't be exposed to this implementation detail.
https://gist.run?id=2686e551dc3b93c494fa9cc8a2aace09
picker.html
<template>
<label repeat.for="item of itemsSource" style="display: block">
<input type="radio" value.bind="item" checked.bind="value">
<template replaceable part="item-template">${item}</template>
</label>
</template>
picker.js
import {bindable, processContent} from 'aurelia-templating';
import {bindingMode} from 'aurelia-binding';
import {FEATURE} from 'aurelia-pal';
#processContent(makePartReplacementFromContent)
export class Picker {
#bindable itemsSource = null;
#bindable({ defaultBindingMode: bindingMode.twoWay }) value = null;
}
function makePartReplacementFromContent(viewCompiler, viewResources, element, behaviorInstruction) {
const content = element.firstElementChild;
if (content) {
// create the <template>
const template = document.createElement('template');
// support browsers that do not have a real <template> element implementation (IE)
FEATURE.ensureHTMLTemplateElement(template);
// indicate the part this <template> replaces.
template.setAttribute('replace-part', 'item-template');
// replace the element's content with the <template>
element.insertBefore(template, content);
element.removeChild(content);
template.content.appendChild(content);
return true;
}
}
usage
<template>
<require from="picker"></require>
<h1>Default Item Template</h1>
<picker items-source.bind="colors" value.bind="color"></picker>
<h1>Custom Item Template</h1>
<picker items-source.bind="colors" value.bind="color">
<em css="color: ${item}">
${item}
</em>
</picker>
</template>

Categories