Writing nodejs scripts inside nextjs HTML - node.js

I am programing my new website in a structure with nodejs, nextjs and expressjs. The problem is tho that I want to write a if statement inside of the HTML part which in that case it will write the if statement as normal html on the website:
const Admin = () => (
<AdminLayout>
<style global jsx>
{
`body {
background: #eff0f3;
}`
}
</style>
<div className="jumbotron" style={jumbotron}>
if (1=1) {
<h3>Please select a tool first.</h3>
} else {
<h3>Something is wrong :/ .</h3>
}
</div>
</AdminLayout>
)
export default Admin
And the out put is just:
if (1=1)
Please select a tool first.
else
Something is wrong :/ .
as HTML on the website. How would I do this but having the script actually being a script?

Next.js uses React that allows you to write something called jsx, which is what you're calling the "HTML part". You can write JavaScript expressions in jsx, but they need to be wrapper in {} brackets. Otherwise any JS code will actually just be interpreted as a text string in the rendered HTML. Check out the React Docs for Embedding Expressions in JSX.
There's lots of ways to do conditional rendering in React.
Here's one way to rewrite your code using {} to embed an expression and the ternary operator:
const Admin = () => (
<AdminLayout>
<style global jsx>{`
body {
background: #eff0f3;
}
`}</style>
<div className="jumbotron" style={jumbotron}>
{1 == 1 ? (
<h3>Please select a tool first.</h3>
) : (
<h3>Something is wrong :/ .</h3>
)}
</div>
</AdminLayout>
)
export default Admin

Related

Display edited/styled text - react

I am building a web app for posting announcements. The user get to use a rich text editor, meaning he can make letters bold, underline them and so one. I am then saving this text with the description "content" in my mongodb database as a string. Every post has a title and a content. When i am displaying the post instead of showing "this text is strong" it is showing "< strong>this text is strong< /strong>". (added a space in < strong> cause it would make it strong otherwise. you get what i mean :P ) obviously this is not happening only in the strong case but with all the edits. for example in paragraphs its like this < p> paragraph < /p> and so on.
How can i display the content like its meant to be (styled) and not just as a string with no edits and style? Maybe it's the fact that i store it in my db as a string? but then what type should i store it as?
Posting images for reference
Allowing this is pretty dangerious, to be honest - you have to be EXTREMELY careful on what you allow and how you are sanitizing input (not allowing script tags, etc..)..
I wouldn't recommend doing this...
The reason this happens is because React is sanitizing the input for you (essentially turning any html into just a plain string - not true sanitization but you get the point)... if you want to render user input HTML, you have to use dangerouslySetInnerHTML - it must be presented in the following format: { __html: '<p>The Dangerous HTML</p>' }
const { useState, dangerouslySetInnerHTML } = React;
const { render } = ReactDOM;
function App() {
const [html, setHtml] = useState();
const handleChange = event => {
setHtml({ __html: event.target.value});
}
return (
<div>
<h3>Enter some html</h3>
<input onChange={handleChange} type="text" />
{html && <div dangerouslySetInnerHTML={html} />}
</div>
);
}
render(<App />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>

React-like refs in lit-html / lit-element?

Does lit-html have by any change something like React's ref feature?
For example in the following pseudo-code inputRef would be a callback function or an object { current: ... } where lit-html could pass/set the HTMLElement instance of the input element when the input element is created/attached.
// that #ref pseudo-attribute is fictional
html`<div><input #ref={inputRef}/></div>`
Thanks.
In lit-element you can use #query property decorator. It's just syntactic sugar around this.renderRoot.querySelector().
import { LitElement, html, query } from 'lit-element';
class MyElement extends LitElement {
#query('#first')
first;
render() {
return html`
<div id="first"></div>
<div id="second"></div>
`;
}
}
lit-html renders directly to the dom so you don't really need refs like you do in react, you can use querySelector to get a reference to the rendered input
Here's some sample code if you were only using lit-html
<html>
<head>
<title>lit-html example</title>
<script type="module">
import { render, html } from 'https://cdn.pika.dev/lit-html/^1.1.2';
const app = document.querySelector('.app');
const inputTemplate = label => {
return html `<label>${label}<input value="rendered input content"></label>`;
};
// rendering the template
render(inputTemplate('Some Label'), app);
// after the render we can access it normally
console.log(app.querySelector('input').value);
</script>
</head>
<body>
<div class="app"></div>
<label>
Other random input
<input value="this is not the value">
</label>
</body>
</html>
If you're using LitElement you could access to the inner elements using this.shadowRoot.querySelector if you're using shadow dom or this.querySelector if you aren't
As #WeiChing has mentioned somewhere above, since Lit version 2.0 you can use the newly added directive ref for that:
https://lit.dev/docs/templates/directives/#ref
-- [EDIT - 6th October 2021] ----------------------------
Since lit 2.0.0 has been released my answer below
is completely obsolete and unnecessary!
Please check https://lit.dev/docs/api/directives/#ref
for the right solution.
---------------------------------------------------------
Even if this is not exactly what I have asked for:
Depending on the concrete use case, one option to consider is the use of directives.
In my very special use-case it was for example (with a little luck and a some tricks) possible to simulate more or less that ref object behavior.
const inputRef = useElementRef() // { current: null, bind: (special-lit-html-directive) }
...
return html`<div><input ref=${inputRef.bind}/></div>`
In my use case I could do the following:
Before rendering, set elementRef.current to null
Make sure that elementRef.current cannot be read while the component is rerendered (elementRef.current is not needed while rendering and an exception will be thrown if someone tries to read it in render phase)
That elementRef.bind directive will fill elementRef.current with the actual DOM element if available.
After that, elementRef.current can be read again.
For lit-html v1, you can define your own custom Derivative:
import { html, render, directive } from "lit-html";
function createRef(){ return {value: null}; }
const ref = directive((refObj) => (attributePart) => {
refObj.value = attributePart.committer.element;
});
const inputRef = createRef();
render(html`<input ref=${ref(inputRef)} />`;
// inputRef.value is a reference to rendered HTMLInputElement

How to use jsx in preact via cdn?

got this code from preact's site, and try to make it work without babel building process, but failed, anybody knows if this is possible? Thanks,
http://jsfiddle.net/e281k4wz/117/
'use strict';
const { Component, h, render } = window.preact;
render((
<div id="foo">
<span>Hello, world!</span>
<button onClick={ e => alert("hi!") }>Click Me</button>
</div>
), document.body);
Yes. You have to include babel before your jsx code and use the script as type="text/babel" see the following example with react
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/#babel/standalone/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/babel">
class App extends React.Component {
render() {
return (
<div className="app-content">
<h1>Hello from React</h1>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'));
</script>
</body>
</html>
You cannot directly use the JSX into the JavaScript as it's a invalid syntax.
For running the preact into the client you have to either transpile the jsx code into valid javascript or use the helper method (Component , h , render) provided by preact.
HTML
<h1>Render by Preact client library using h and render function</h1>
<div id="preact">
</div>
JavaScript
var Component = window.preact.Component,
h = window.preact.h,
render = window.preact.render;
var PreactApp = function (props){
return h('h1',
{className: ''},
'Hello from Preact world!');
}
render(PreactApp(),document.getElementById("preact"));
Here in JS if you see h ( converting jsx to vdom ) and render (converting vdom to html ) function actually do the magic. Read more about from the official documentation - https://preactjs.com/guide/api-reference
Working example - https://jsfiddle.net/97125m3z/2/
Technically it is possible by using the HTM package, as long as you're targeting recent browsers that understand template strings. See https://github.com/developit/htm for details.
However, this will render slower than simply creating the components using h() as it is a whole heap of string parsing. It also makes it difficult to use syntax highlighting in your IDE, which makes debugging frustrating.
I used HTM when I was first getting used to using Preact without a build step, but very quickly replaced it with manually creating the components and eliminated the JSX.
You get a better understanding of how everything fits together if you don't use the JSX abstraction. Babel compiles it down into createElement calls anyway.

Using Fragment to insert HTML rendered on the back end via dangerouslySetInnerHTML

I used to compile and insert JSX components via
<div key={ ID } dangerouslySetInnerHTML={ { __html: HTML } } />
which wrapped my HTML into a <div>:
<div>my html from the HTML object</div>
Now react > 16.2.0 has support for Fragments and I wonder if I can use that somehow to avoid wrapping my HTML in a <div> each time I get data from the back end.
Running
<Fragment key={ ID } dangerouslySetInnerHTML={ { __html: HTML } } />
will throw a warning
Warning: Invalid prop `dangerouslySetInnerHTML` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.
in React.Fragment
Is this supported yet at all? Is there another way to solve this?
Update
Created an issue in the react repo for it if you want to upvote it.
Short Answer
Not possible:
key is the only attribute that can be passed to Fragment. In the
future, we may add support for additional attributes, such as event
handlers.
https://reactjs.org/docs/fragments.html
You may want to chime in and suggest this as a future addition.
https://github.com/facebook/react/issues
In the Meantime
You may want to consider using an HTML parsing library like:
https://github.com/remarkablemark/html-react-parser
Check out this example to see how it will accomplish your goal:
http://remarkablemark.org/blog/2016/10/07/dangerously-set-innerhtml-alternative/
In Short
You'll be able to do this:
<>
{require('html-react-parser')(
'<em>foo</em>'
)}
</>
Update December 2020
This issue (also mentioned by OP) was closed on Oct 2, 2019. - However, stemming from the original issue, it seems a RawHTML component has entered the RFC process but has not reached production, and has no set timeline for when a working solution may be available.
That being said, I would now like to allude to a solution I currently use to get around this issue.
In my case, dangerouslySetInnerHTML was utilized to render plain HTML for a user to download; it was not ideal to have additional wrapper tags included in the output.
After reading around the web and StackOverflow, it seemed most solutions mentioned using an external library like html-react-parser.
For this use-case, html-react-parser would not suffice because it converts HTML strings to React element(s). Meaning, it would strip all HTML that wasn't standard JSX.
Solution:
The code below is the no library solution I opted to use:
//HTML that will be set using dangerouslySetInnerHTML
const html = `<div>This is a div</div>`
The wrapper div within the RawHtml component is purposely named "unwanteddiv".
//Component that will return our dangerouslySetInnerHTML
//Note that we are using "unwanteddiv" as a wrapper
const RawHtml = () => {
return (
<unwanteddiv key={[]}
dangerouslySetInnerHTML={{
__html: html,
}}
/>
);
};
For the purpose of this example, we will use renderToStaticMarkup.
const staticHtml = ReactDomServer.renderToStaticMarkup(
<RawHtml/>
);
The ParseStaticHtml function is where the magic happens, here you will see why we named the wrapper div "unwanteddiv".
//The ParseStaticHtml function will check the staticHtml
//If the staticHtml type is 'string'
//We will remove "<unwanteddiv/>" leaving us with only the desired output
const ParseStaticHtml = (html) => {
if (typeof html === 'string') {
return html.replace(/<unwanteddiv>/g, '').replace(/<\/unwanteddiv>/g, '');
} else {
return html;
}
};
Now, if we pass the staticHtml through the ParseStaticHtml function you will see the desired output without the additional wrapper div:
console.log(ParseStaticHtml(staticHtml));
Additionally, I have created a codesandbox example that shows this in action.
Notice, the console log will throw a warning: "The tag <unwanteddiv> is unrecognized in this browser..." - However, this is fine because we intentionally gave it a unique name so we can easily differentiate and target the wrapper with our replace method and essentially remove it before output.
Besides, receiving a mild scolding from a code linter is not as bad as adding more dependencies for something that should be more simply implemented.
i found a workaround
by using react's ref
import React, { FC, useEffect, useRef } from 'react'
interface RawHtmlProps {
html: string
}
const RawHtml: FC<RawHtmlProps> = ({ html }) => {
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
if (!ref.current) return
// make a js fragment element
const fragment = document.createDocumentFragment()
// move every child from our div to new fragment
while (ref.current.childNodes[0]) {
fragment.appendChild(ref.current.childNodes[0])
}
// and after all replace the div with fragment
ref.current.replaceWith(fragment)
}, [ref])
return <div ref={ref} dangerouslySetInnerHTML={{ __html: html }}></div>
}
export { RawHtml }
Here's a solution that works for <td> elements only:
type DangerousHtml = {__html:string}
function isHtml(x: any): x is DangerousHtml {
if(!x) return false;
if(typeof x !== 'object') return false;
const keys = Object.keys(x)
if(keys.length !== 1) return false;
return keys[0] === '__html'
}
const DangerousTD = forwardRef<HTMLTableCellElement,Override<React.ComponentPropsWithoutRef<'td'>,{children: ReactNode|DangerousHtml}>>(({children,...props}, ref) => {
if(isHtml(children)) {
return <td dangerouslySetInnerHTML={children} {...props} ref={ref}/>
}
return <td {...props} ref={ref}>{children}</td>
})
With a bit of work you can make this more generic, but that should give the general idea.
Usage:
<DangerousTD>{{__html: "<span>foo</span>"}}</DangerousTD>

Conditionals within script. in jade

In Jade, is it possible to create a conditional if statement in a dynamicscript section?
For example:
doctype html
html
head
script.
-if( locals.display_JS )
console.log("Display_JS is TRUE")
-else
console.log("Display_JS is FALSE")
(locals.display_JS is a parameter pass to Jade in res.render.)
If display_JS is true, the desired output should look like:
<script ...>console.log("Display_JS is TRUE")</script>
However the output is:
<script>
-if( locals.display_JS )
console.log("Display_JS is TRUE")
-else
console.log("Display_JS is FALSE")
</script>
It could be that I am thinking wrong. My objective is to render different javascript functions based on parameters sent to res.render.
It can be done the other way, use the . whenever you want to nest javascript code.
doctype html
html
head
script
if( locals.display_JS )
.
/** Some JS code **/
console.log("Display_JS is TRUE")
else
.
console.log("Display_JS is FALSE")
Jade will not mess with anything within a script block. If you really need to use jade logic inside a script block you can get a little tricky and do something like this:
Router Code:
router.get('/', function(req, res){
res.render('index', {run_this:true});
});
Jade Code:
div
| <script type='text/javascript'>
if(run_this)
| console.log("Ran this!");
else
| console.log("Didn't run this");
| </script>
Another approach to running logic based on jade variables within a script tag is to do something like this:
script.
if(!{run_this}){
console.log("Ran This!");
}
When you use script. everything that comes after will be interpreted as plain text by jade. If you need to mix markup and plain text you can use |. For example:
script
| function bar(){
if(true)
| console.log("Ran this")
else
| console.log("Don't run this")
| }

Resources