Wordpress Gutenberg InnerBlock.Content is not being saved or rendered - javascript

I am creating a custom block in Gutenberg via custom plugin. My custom block contains InnerBlocks. The edit function appears to be working correctly, as I can add the block to the page, and place new block elements inside the block as intended. The issue arrises when I reload the page. After I update the page and reload the editor, all of the InnerBlock elements are gone. They are not being saved, and not being rendered on the frontend either. Unless I'm crazy, my save function is not built correctly. Any help would be great. I am well versed in Wordpress and JS, but new to React and Gutenberg. Thanks for any help!
( function( blocks, element, editor ) {
const el = element.createElement;
const { registerBlockType } = blocks;
const InnerBlocks = editor.InnerBlocks;
registerBlockType( 'dab/nest', {
title: 'Disruptive Nest',
icon: 'layout',
category: 'disruptive-blocks',
keywords: [ 'base', 'build', 'custom' ],
edit: function( props ) {
return (
el( 'div', {className: props.className + ' dab-full'},
el( 'div', {className: 'dab-content'},
el( InnerBlocks )
)
)
);
},
save: function( props ) {
return (
el( 'div',
el( 'div',
el( InnerBlocks.Content, null )
)
)
);
},
});
})( window.wp.blocks,
window.wp.element,
window.wp.blockEditor
);

I found this in the Block Editor Handbook ([https://developer.wordpress.org/block-editor/developers/block-api/block-edit-save/#classname):
"This is automatically added in the save method, but not on edit" [on the topic of props.className]. That is why I didn't have the classes mirrored initially. Reading it again led me to realize that mirroring the classNames on the "save" function isn't what fixed it, but just having the {} in there after each of the parent el( 'div',, even if you don't specify anything, is what fixed the function.
So, it works like this, and the className is automatically added to the first el( 'div',:
save: function( props ) {
return (
el( 'div', {},
el( 'div', {},
el( InnerBlocks.Content )
)
)
);
},
Thanks, #niklas for helping me realize this.

Related

Open a dialog on row selection [material-table]

Is there a way to open a details dialog when clicking on a specific row of the table. The issue is regarding material-table (https://material-table.com/).
Thanks in advance! :)
There isn't a native solution to display a popup like you want with material-table. But you can achieve this.
You have a props in MaterialTable called onRowClick.
<MaterialTable
onRowClick={(evt, selectedRow) => yourFunction(selectedRow)}
/>
Using this props you can define your own function to open a popper (https://material-ui.com/components/popper/) or whatever popup type component you want on row click and display the informations of the selected Table row in it.
That way you can even make a request to get more details info with the id you get to display even more details info !
Exemple:
const alertMyRow = (selectedRow) => (
// here i can request something on my api with selectedRow.id to get additional
// datas which weren't displayed in the table
alert(`name: ${selectedRow.name}, surname: ${selectedRow.surname}`);
);
return(){
render(
<MaterialTable
columns={[
{ title: 'ID', field:'id' },
{ title: 'Name', field: 'name' },
{ title: 'Surname', field: 'surname' },
{ title: 'Phone Number', field: 'phone' },
]}
datas={[...]}
onRowClick={(evt, selectedRow) => alertMyRow(selectedRow)}
/>
)
);
Don't hesitate if i wasn't clear enough ;)

How to add click event with React createElement

Following is the code that I'm using to create an HTML tag. I want to add a click event on this. How can I add this?
let elem = React.createElement(
this.props.tag,
{
style: this.props.style,
id: this.props.id
onClick: ()
},
[this.props.text]
)
If you are creating an HTML tag, you simply need to pass on the onClick as a function to the element as props. With React.createElement you can write it like
let elem = React.createElement(
this.props.tag,
{
style: this.props.style,
id: this.props.id
onClick: () => {console.log('clicked')}
},
[this.props.text]
)
You could also pass a predefined function like below
let elem = React.createElement(
this.props.tag,
{
style: this.props.style,
id: this.props.id
onClick: this.handleClick.bind(this)
},
[this.props.text]
)

WordPress Block Registration ES6 /ESNext Uncaught SyntaxError: Unexpected token <

I have been looking everywhere to see why my code will not work. I am trying to create a WordPress Gutenberg Block using the following code. I have tested 3 versions of code from different websites and have not been able to figure out why it fails on <div className={className}>
PHP - functions.php
function register_block_editor_assets() {
$dependencies = array(
'wp-blocks', // Provides useful functions and components for extending the editor
'wp-i18n', // Provides localization functions
'wp-element', // Provides React.Component
'wp-components' // Provides many prebuilt components and controls
);
wp_register_script( 'my-block-editor', get_stylesheet_directory_uri().'/js/testing2.js', $dependencies );
}
add_action( 'admin_init', 'register_block_editor_assets' );
function register_block_assets() {
wp_register_script( 'my-block', get_stylesheet_directory_uri().'/js/testing2.js', array( 'jquery' ) );
}
add_action( 'init', 'register_block_assets' );
JS - testing2.js
const { registerBlockType } = wp.blocks;
const { Fragment } = wp.element;
const {
RichText,
BlockControls,
AlignmentToolbar,
} = wp.editor;
registerBlockType( 'example/example-block', {
title = __('Example Block', 'example'),
icon = 'screenoptions',
category = 'common',
attributes = {
content: { // Parsed from HTML selector
source: 'children',
selector: 'p',
type: 'array'
},
textColor: { // Serialized by default
type: 'string'
},
isPinned: { // Pulled from REST API
type: 'boolean',
source: 'meta',
meta: 'example_is_pinned'
}
},
edit = ({ attributes, setAttributes, className, isSelected }) => {
const {
content
} = attributes
return (
<div className={className}>
<RichText
className="example-content"
value={content}
onChange={(content) =>setAttributes({ content })} />
</div>
)
}),
save = ({ attributes }) {
const {
content
} = attributes
return (
<div>
<p>{content}</p>
</div>
)
})
};
You have a syntax error in your js file.
Try this code
const { registerBlockType } = wp.blocks;
const { Fragment } = wp.element;
const {
RichText,
BlockControls,
AlignmentToolbar,
} = wp.editor;
registerBlockType( 'example/example-block', {
title :__('Example Block', 'example'),
icon : 'screenoptions',
category : 'common',
attributes : {
content: { // Parsed from HTML selector
source: 'children',
selector: 'p',
type: 'array'
},
textColor: { // Serialized by default
type: 'string'
},
isPinned: { // Pulled from REST API
type: 'boolean',
source: 'meta',
meta: 'example_is_pinned'
}
},
edit(props){
const {attributes, setAttributes, className} = props;
const {
content
} = attributes
return (
<div className={className}>
<RichText
className="example-content"
value={content}
onChange={(content) =>setAttributes({ content })} />
</div>
)
},
save(props){
const {attributes} = props;
const {
content
} = attributes
return (
<div>
<p>{content}</p>
</div>
)
} });
You need to transpile jsx and react components into regular javascript syntax, that's why you get that error. You can use a transpiler like babel.
JSX is a language extension that requires transpilation. You can read more about it from its spec: https://github.com/facebook/jsx
If you are not familiar at all, please check these links:
https://reactjs.org/docs/introducing-jsx.html
https://reactjs.org/docs/jsx-in-depth.html

Targeting a class element node inside react function of createElement() class

I want to grab the current node of a function inside a React.createElement() function.
return React.createClass({
getInitialState: function() {
return ({
expand: false
});
},
expandLaunch: function() {
this.setState({
expand: true
});
// want to do something like
// $('.text').css('display','block');
},
render: function() {
var titlebar = React.createElement(
'div',
{className: 'titlebar', onClick: this.expandLaunch},
'Launcher'
);
//........
var text = React.createElement(
'div',
{className: 'text'},
textarea
);
return React.createElement(
'div',
{className: 'box-wrapper'},
titlebar,
text
);
}
});
So with the expandLaunch() function I wanted to target the element so I can manipulate the css and other possible functionality. FYI I am not using JSX, just regular jQuery.
Use ref.
return React.createClass({
getInitialState: function() {
return ({
expand: false
});
},
expandLaunch: function() {
this.setState({
expand: true
});
$(this.refs.text).css('display','block');
},
render: function() {
var titlebar = React.createElement(
'div',
{className: 'titlebar', onClick: this.expandLaunch},
'Launcher'
);
//........
var text = React.createElement(
'div',
{className: 'text', ref: 'text'},
textarea
);
return React.createElement(
'div',
{className: 'box-wrapper'},
titlebar,
text
);
}
});
I do urge you to use the tools React gives you to achieve this, via dynamic classNames or inline styles, rather than using jquery, which in many ways should be considered orthogonal to React.

Uncaught SyntaxError: Unexpected token < in React

I'm working on a react project and trying to display a dialog with react-bootstrap. I just copied a working react-bootstrap snippet in a js file but it's not working for me, I'm having Uncaught SyntaxError: Unexpected token < next to the <div className='static-modal'> line.
Here is the content of the js file:
(function (context) {
// notification view
TheGraph.Notification = React.createFactory( React.createClass({
//TheGraph.Notification = React.createClass({
componentDidMount: function () {
},
handleHide: function () {
alert('Close me!');
},
render: function () {
return (
<div className='static-modal'>
<Modal title='Modal title' bsStyle='primary' backdrop={false} animation={false} container={mountNode} onRequestHide={handleHide}>
<div className='modal-body'>
One fine body...
</div>
<div className='modal-footer'>
<Button>Close</Button>
<Button bsStyle='primary'>Save changes</Button>
</div>
</Modal>
</div>
);
}
});
})(this);
When I put use " in return line as follows:
return ("<div className='static-modal'><Modal title='Modal title' bsStyle='primary' backdrop={false} animation={false} container={mountNode} onRequestHide={handleHide}><div className='modal-body'>One fine body...</div><div className='modal-footer'><Button>Close</Button><Button bsStyle='primary'>Save changes</Button></div></Modal></div>");
I get this error:
Uncaught Error: Invariant Violation: ReactCompositeComponent.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object
Any idea what is the mistake here?
The code that you are using inside render is JSX , browsers as of now doesn't understand jsx . So we need transpilers to convert them to pure JavaScript .
You need to have a build process that transpiles your jsx code into javascript and then you should load that transpiled js in your HTML.
But if you just quickly want to play with react without setting up the build process , you can go here and do that manually every time and paste that inside render
React.createElement(
'div',
{ className: 'static-modal' },
React.createElement(
Modal,
{ title: 'Modal title', bsStyle: 'primary', backdrop: false, animation: false, container: mountNode, onRequestHide: handleHide },
React.createElement(
'div',
{ className: 'modal-body' },
'One fine body...'
),
React.createElement(
'div',
{ className: 'modal-footer' },
React.createElement(
Button,
null,
'Close'
),
React.createElement(
Button,
{ bsStyle: 'primary' },
'Save changes'
)
)
)
);

Categories