Can not pass on property from one Component to another - reactjs

I trie to pass an Object from my Card Component to my FloatingActionButtons Component.
But i don't work i got the error:
TypeError: Cannot read property 'name' of undefined
If i pass just one attribute from the Object like name,abteilung,bereich,... then it works.
So, how can i pass the whole Object to the Component ?
Card.js
import FloatingButton from "./FloatingActionButtons";
export default function Card() {
const plan = new Plan("Max Mustermann", "woamen.jpg", "ITH/A", "IT", 13);
return (
<FloatingButton azubi={plan}></FloatingButton>
);
FloatingActionButtons.js
export default function FloatingActionButtons({ azubi }) {
<Typography gutterBottom>{azubi.name}</Typography>
}
Plan.js
export default class Plan {
constructor(name, image, abteilung, bereich, azubis) {
this.name = name;
this.image = image;
this.abteilung = abteilung;
this.bereich = bereich;
this.azubis = azubis;
}
}

I've made a Codesandbox attempting to recreate your issue and it appears to be fine. Please compare to your own and check for any syntax issues: for example, your FloatingActionButtons.js snippet doesn't have a return keyword however the error you're getting doesn't match up with that issue.

Based on the snippet the code must work fine. Make sure you're not missing any value while updating the components. Here is the working snippet based on your code:
class Plan {
constructor(name, image, abteilung, bereich, azubis) {
this.name = name;
this.image = image;
this.abteilung = abteilung;
this.bereich = bereich;
this.azubis = azubis;
}
}
function Card() {
const plan = new Plan("Max Mustermann", "woamen.jpg", "ITH/A", "IT", 13);
return (<FloatingButton azubi={plan} />);
}
function FloatingButton({
azubi
}) {
return (<p> {azubi.name}</p>);
}
ReactDOM.render(<Card />, document.getElementById('root'));
<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>
<div id="root"></div>

Related

call function in React functional component

I am trying to call a function from a div like the following
<div id='div_abstract'>
{content.abstract && content.abstract.length ? (
<article id="abstract" onMouseUp={spanSelect}>{content.abstract </article>) : ''}
</div>
My functional component is structured like this
export default function ExternalInfos(props) {
...
function spanSelect() { ... }
return(
...
);
}
And the function I'm trying to call is
let table = [];
function spanSelect() {
var span = document.createElement("span");
span.setAttribute("id","span");
if (window.getSelection()) {
var text = window.getSelection();
if (text.rangeCount) {
var range = text.getRangeAt(0).cloneRange();
range.surroundContents(span);
text.removeAllRanges();
text.addRange(range);
};
};
let object = window.getSelection().toString();
table.push(object);
const annotation = document.getElementById("annotationArea");
annotation.updateObjectAnnotation(table);
}
But nothing happens when I select text from my div and it doesn't return an error.
How do I solve this?
You need to capitalize the event handler prop: onMouseUp.
From the React docs (https://reactjs.org/docs/handling-events.html):
"React events are named using camelCase, rather than lowercase."

elegant way to downgrade all angular components for angular js

My app is supposed to migrate from angularjs to angular.
I'm creating new angular components. Is there an elegant way to automatically import and downgrade component?
Current code:
import { ColorPickerComponent } from './angular-comp/color-picker/color-picker.component';
import {FileSelectComponent } from './angular-comp/file-select/file-select.component';
export default angular
.module('kn-components', myModuleNames)
.directive('colorPicker', downgradeComponent({component: ColorPickerComponent}))
.directive('fileSelect', downgradeComponent({component: FileSelectComponent}))
.name;
Each time I create a component I need to do it, it's quite verbose....
For my angularjs component, for example, I did the following:
const myModuleNames = [];
const loadModules = require.context(".", true, /\.module.js$/);
loadModules.keys().forEach(function (key) {
if(loadModules(key).default)
myModuleNames.push(loadModules(key).default);
});
then:
export default angular
.module('kn-components', myModuleNames)
and all my modules/components are imported
If the goal is to get rid of boilerplate code, you can get list of components to upgrade, get the selector name for each component and register corresponding directive
Get list of your components. This depends on your code structure. The simplest option is to just explicitly return components you need to downgrade. Or you can use require.context as you did in your example.
function getComponents() {
// depends on how your components are organized
// for example, iterate over require.context(".", true, /\.component.ts$/);
// or return fixed array
return [ColorPickerComponent, FileSelectComponent];
}
For each component get the selector name. If you don't use AOT compilation, you can get selector value from the #Component decorator. But if you do use it, that won't work and you can make a selector from a component name
function getComponentSelector(component) {
// if you don't need AOT
return toCamelCase(component.__annotations__[0].selector);
// if you do need it
let name: string = component.name;
const suffix = 'Component';
if (name.endsWith(suffix)) {
name = name.substr(0, name.length - suffix.length);
}
return uncapitalize(name);
}
function toCamelCase(selector: string) {
const splitted = selector.split('-');
for (let i = 1; i < splitted.length; i++) {
splitted[i] = capitalize(splitted[i]);
}
return splitted.join('');
}
function capitalize(name: string) {
return name.charAt(0).toUpperCase() + name.slice(1);
}
function uncapitalize(name: string) {
return name.charAt(0).toLowerCase() + name.slice(1);
}
Iterate over your components and register downgraded components
downgradeComponents(angular.module('kn-components'));
function downgradeComponents(module: ng.IModule) {
const components = getComponents();
for (const component of components) {
const selector = getComponentSelector(component);
module.directive(selector, downgradeComponent({ component }));
}
}

React how to convert string to object property

In a React project, I want to dynamically access an object property name using a string variable I pass through props. I am able to pass a value as string; however, when I try to use it to access the object property it doesn't work.
Here's an example:
const passedField = 'title'; // this comes from props
const book = { title: 'Sample title', content : 'some content' };
book.passedField; // returns undefined
I access title like this book.title
I want to access it like book.passedField but I get undefined on console.
How can I achieve this?
book.passedField will be returning undefined because there is no passedField in book. Instead use bracket notation as below
const book = { title: 'abc', pages: 350 };
const passedField = 'pages';
console.log(book[passedField])
What you're using is called a dot notation property accessor. What you need to use is a bracket notation property accessor.
book.title and book['title'] are the same, which means you can assign title to a variable, and use the variable name instead like this.
const passedField = 'title';
book[passedField]; // same as book['title']
You might only be familiar with bracket notation with Arrays, like myArray[0], but they work with Objects too! (because Arrays in JavaScript are actually objects)
Solution
const books = [
{
title: 'The Art of War',
contents: 'An ancient Chinese military treatise dating from the Spring and Autumn Period'
},
{
title: 'Winnie the Pooh',
contents: 'Pooh is naive and slow-witted, but he is also friendly, thoughtful, and steadfast.'
}
]
class Book extends React.Component {
constructor(props) {
super(props);
this.findBookByFilter = this.findBookByFilter.bind(this);
}
findBookByFilter() {
let result = null
if (books) {
const {passedFilterField, filterText} = this.props;
result = books.filter(book => {
return book[passedFilterField].toLowerCase().includes(filterText.toLowerCase());
}).map(book => <p>{book.title}</p>)
}
return result;
}
render () {
return this.findBookByFilter();
}
}
class App extends React.Component {
render() {
return (
<Book
passedFilterField='contents'
filterText='thoughtful'
/>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<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>
<div id="root"></div>
Notes
I moved your {book && book.filter} logic to a function called findBookByFilter
I used includes instead of indexOf in the filter
I used destructuring assignment for this.props
I return the matched title, rather than <Link /> for demo purposes.
Documentation
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
You can access object properties using book[passedField]

It's okay to define an object's property value relatively to its sibling?

For example:
state={
viewIndex:0,
travelerIndex: 100,
viewValue: (this.stateviewIndex * this.state.travelerIndex)
}
Here we can see that viewValue is defined relatively to viewIndex and travelerIndex. It seems a few recursive to me and I wonder if it's okay to do the thing like that.
Any hint would be great,
thanks
I would create a local function that computes the total value from the state instead of adding a layer of complexity into the state. I've created an example below. You can use the return value to do whatever.
class App extends React.Component {
state = {
tomsWallet: 50,
hannahsPurse: 49,
}
getTotalBalance = () => {
return (this.state.tomsWallet + this.state.hannahsPurse).toFixed(2);
}
render() {
return (
<div>Total Balance: £{this.getTotalBalance()}</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
<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>
<div id="root"></div>

How can I add properties to a react component passed as a variable?

My scenario is that I'm creating a render() function in a controller (not React related) to render views with the option of specifying a layout. That way I can have multiple different layout components, all accepting a content property, that can be rendered in a simple way. Here's what I'm trying to do in a nutshell:
render: function(content, layout) {
layout = layout || <Layout />;
layout.setProps({ content: content });
React.render(layout, document.body);
}
Can it be done? Or if you think it can be done but it's a bad idea, please let me know why.
There are a couple ways you could approach this.
The simplest is to pass the layout's type and properties separately:
function render(content, layoutType, layoutProperties) {
layoutType = layoutType || Layout;
layoutProperties = layoutProperties || {};
var props = { content: content };
for (var key in layoutProperties) {
props[key] = layoutProperties[key];
}
var layout = React.createElement(layoutType, props);
React.render(layout, document.body);
}
render(<div>Test 1</div>);
render(<div>Test 2</div>, CustomLayout, { title: "Test Title" });
JSFiddle example: http://jsfiddle.net/BinaryMuse/hjLufbkz/
If you want to pass a fully-realized ReactElement as the layout instead, you could use React.addons.cloneWithProps (or, in v0.13 RC2 and later, React.cloneElement):
function render(content, layout) {
var props = { content: content };
layout = layout || <Layout />;
layout = React.addons.cloneWithProps(layout, props);
React.render(layout, document.body);
}
render(<div>Test 1</div>);
render(<div>Test 2</div>, <CustomLayout title="Test Title" />);
JSFiddle example: http://jsfiddle.net/BinaryMuse/8krawhx4/
I'm a big fan of using this.props.children to nest elements; note that you can modify both the techniques above to do so:
function render(content, layoutType, layoutProperties) {
layoutType = layoutType || Layout;
layoutProperties = layoutProperties || {};
var layout = React.createElement(layoutType, layoutProperties, content);
React.render(layout, document.body);
}
JSFiddle example: http://jsfiddle.net/BinaryMuse/6g8uyfp4/
and
function render(content, layout) {
layout = layout || <Layout>{content}</Layout>;
layout = React.addons.cloneWithProps(layout, {children: content});
React.render(layout, document.body);
}
JSFiddle example: http://jsfiddle.net/BinaryMuse/nadv297h/
Of course, if one of your custom layout components already utilizes this.props.children for other purposes, the original technique with cloneWithProps/cloneElement and this.props.content works just fine. (JSFiddle example: http://jsfiddle.net/BinaryMuse/b5ncfnqh/)

Resources