DetailsList component is not taking into account selection property - reactjs

I have created the following sample application to try and simplify as much as possible an issue I am having as part of a larger application I am working on.
The issue has to do with the selection property of the DetailsList component in office-ui-fabric-react.
I have included the main components of the sample application below to try and illustrate my issue.
App.tsx
import * as React from 'react';
import './App.css';
import { ClickedItemsList } from './ClickedItemsList';
import { GenerateItemButton } from './GenerateItemButton';
import { ItemSelectionStore } from './ItemSelectionStore';
class App extends React.Component {
public itemSelectionStore: ItemSelectionStore = new ItemSelectionStore();
public render() {
return (
<div>
<GenerateItemButton store={this.itemSelectionStore} />
<ClickedItemsList store={this.itemSelectionStore} />
</div>
);
}
}
export default App;
ItemSelectionStore.tsx
import * as React from 'react';
import './App.css';
import { ClickedItemsList } from './ClickedItemsList';
import { GenerateItemButton } from './GenerateItemButton';
import { ItemSelectionStore } from './ItemSelectionStore';
class App extends React.Component {
public itemSelectionStore: ItemSelectionStore = new ItemSelectionStore();
public render() {
return (
<div>
<GenerateItemButton store={this.itemSelectionStore} />
<ClickedItemsList store={this.itemSelectionStore} />
</div>
);
}
}
export default App;
GenerateItemButton.tsx
import * as React from 'react';
import { ItemSelectionStore } from './ItemSelectionStore';
export interface IGenerateItemButtonProps {
store: ItemSelectionStore
}
export class GenerateItemButton extends React.Component<IGenerateItemButtonProps> {
public render() {
return (
<button onClick={this.handleClick}/>
)
}
private handleClick = () =>
this.props.store.onAddItemButtonClicked();
}
ClickedItemList
import { observer } from 'mobx-react';
import {CheckboxVisibility, DetailsList, IColumn, IObjectWithKey, Selection, SelectionMode } from 'office-ui-fabric-react/lib/DetailsList';
import * as React from 'react';
import { ItemSelectionStore } from './ItemSelectionStore';
export interface IClickedItemsListProps {
store: ItemSelectionStore
}
#observer
export class ClickedItemsList extends React.Component<IClickedItemsListProps> {
private columns: IColumn[] = [{ key: 'key', name: 'Extracted key', fieldName: 'key', minWidth: 150 }];
public render() {
const { store } = this.props;
const selectedItems = store.selectedItems;
// creating items to display
const itemsToDisplay: IObjectWithKey[] = [];
selectedItems.forEach(k => itemsToDisplay.push({'key': k}));
// creating selection
const selection = new Selection();
selection.setItems(itemsToDisplay);
selection.setAllSelected(true);
return (
<DetailsList
items={itemsToDisplay}
selectionPreservedOnEmptyClick={true}
columns={this.columns}
checkboxVisibility={CheckboxVisibility.always}
selectionMode={SelectionMode.multiple}
selection={selection}
/>
)
}
}
When a user clicks on the button a random string is added to a list of items which are dynamically displayed by the ClickedItemsList component.
The items appear as they should on every click but I am having trouble with the selection property.
I want all items added to the list to also be in a selected state but my sample application fails to do so and all items simply appear in a non selected state.
Thoughts ?

Related

How to test the map reference in a react-leaflet custom child component using Enzyme?

I've created a custom component in react-leaflet by extending MapControl. The component doesn't return anything but adds something to the map object it refers to via the props.
Custom Child Component
import { MapControl, withLeaflet } from "react-leaflet";
import * as L from "leaflet";
class Dashboard extends MapControl<any, any> {
public createLeafletElement(props: any) {}
public addDashboard() {
const dashboard = L.control({ position: "topright" });
dashboard.onAdd = function() {
this._div = L.DomUtil.create("div", "dashboard");
this._div.setAttribute("data-test", "component-dashboard");
return this._div;
};
const { map } = this.props.leaflet;
dashboard.addTo(map);
}
componentDidMount() {
this.addDashboard();
}
render() {
return null;
}
}
export default withLeaflet(Dashboard);
Parent/Map component
import React from "react";
import { Map, TileLayer } from "react-leaflet";
import Dashboard from "./Dashboard";
class MapContainer extends React.Component<any> {
public constructor(props: any) {
super(props);
}
render() {
return (
<div data-test="component-map">
<Map
center={this.props.center}
zoomSnap={this.props.zoomSnap}
zoom={this.props.zoom}
style={this.props.style}
>
<TileLayer
url={this.props.url}
attribution={this.props.attribution}
/>
<Dashboard />
</Map>
</div>
);
}
}
export default MapContainer;
While testing the child component Dashboard, how do I initialise map?
(and then check if it contains the dashboard)
I'm using Jest and Enzyme
For Jest the following example demonstrates how to:
create an instance of react-leaflet Map component
ensure a custom control (Dashboard in your case) is instantiated
Example
import React from "react";
import ReactDOM from "react-dom";
import { renderIntoDocument } from "react-dom/test-utils";
import { Map, TileLayer } from "react-leaflet";
import Dashboard from "./Dashboard";
it("Control test", () => {
class TestComponent extends React.Component {
constructor() {
super();
this.controlRef = React.createRef();
}
getControl() {
return this.controlRef.current.leafletElement;
}
render() {
return (
<Map center={[0,0]} zoom={10}>
<Dashboard ref={this.controlRef} />
</Map>
);
}
}
const component = renderIntoDocument(<TestComponent />);
const control = component.getControl();
expect(control).not.toBeNull();
});

How to use 'Inject' without decorator in Mobx with ReactJs

I wonder how to use Inject without decorator.
First, I made this as Store.
//Data/imagedb
import { decorate, observable } from 'mobx';
class imageStore {
list = {
keyword : 'yoyo',
}
}
decorate(imageStore, {
list: observable,
})
export default imageStore;
Second, I made this code to inject Store on it.
//components/Image
import React, { Component } from 'react';
import { observer, inject } from 'mobx-react';
class Image extends Component {
render() {
const onPut2 = {onPut};
return (
<div>
{onPut2}
</div>
);
}
}
export default inject(({ imSt }) => ({
onPut: imSt.list.keyword,
}))(observer(Image));
And finally, this is my last code.
The error is "Onput is not defined" in second code.
import React from 'react';
import Image from 'components/Image';
import { Provider } from 'mobx-react';
import imageStore from 'Data/imagedb'
const imSt = new imageStore();
const Home = () => {
return (
<div>
<Provider imSt={imSt}>
<Image />
</Provider>
</div>
);
};
export default Home;

React native infinite loop while pass the parameter into function

How to call function inside another function>
For example
I have 2 cascade dropdown which value from second dropdown depends on from first dropdown. inside the first dropdown there is a method like this
`onValueChange = {(value)=>{this.props.getSecondValue(value.id)}}.`
My question is why every time I change the value from first dropdown it causes infinite loop in this.props.getSecondValue() function?
How to solve that problem.
Many thanks !
update
here my snippet code
import React, {Component} from 'react';
import {StyleSheet, Text, View, TouchableOpacity, KeyboardAvoidingView, SafeAreaView, ScrollView} from 'react-native';
import {bindActionCreators} from "redux";
import {RootActions} from "../../shared/root-actions";
import connect from "react-redux/es/connect/connect";
import Config from 'react-native-config';
import _ from 'lodash';
import {Dropdown} from 'react-native-material-dropdown';
type Props = {};
const styles = StyleSheet.create({
container: {
flex: 1
}
});
class Index extends Component<Props> {
constructor(props) {
super(props);
this.state = {
point_type_id: '',
point_category_id: '',
}
this._getPointTypes = this._getPointTypes.bind(this);
this._getPointCategories = this._getPointCategories.bind(this);
}
componentDidMount() {
this._getPointTypes();
}
_getPointTypes(){
this.props.getPointTypes();
}
_getPointCategories(point_type_id){
this.props.getPointCategories(point_type_id);
}
render() {
let {
point_type_id,
point_category_id,
} = this.state;
let {
} = this.locationDetailStates;
return (
<View style={styles.container}>
....
<Dropdown
label='Point types'
data={point_types}
labelExtractor = {(value)=>{this._getPointCategories(value.id)}}
/>
<Dropdown
label='Point categories'
data={point_categories}
/>
</View>
);
}
}
function mapStateToProps(state) {
return {
outdoorStates: state.outdoorStates,
locationDetailStates:state.locationDetailStates
}
}
function mapDispatchToProp(dispatch) {
return bindActionCreators(RootActions, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProp)(Index);
Try to refactor like this:
function mapDispatchToProps(dispatch) {
return {
getSecondValue: (id)=>{
//Your code here
}
}
}
class MyClass extends React.Component {
handleChange = (e)=>{
//assign your id from event values
this.props.getSecondValue(id);
}
...
render(){
return (
//inside a tag
onChange = {this.handleChange}
)
}
}

Update Subcomponent with viewer after mutation in relay

I’m new to Relay (with reactjs) and have a problem with updating my UI after a commit mutation in the viewer. In my example I have a Salutation Component with the first name of the user and to simplify this, I put a input field right after the output of the name.
When the user changes the name in the textfield, I send this to my updatemutation and to the API. My problem is that I don’t know how to update the name above the input, after the new name was saved. Could anyone help me - what do I need to do in the updater?
Many thanks!
The "root"-Component:
import React, {Component} from 'react';
import {QueryRenderer, graphql} from 'react-relay';
import environment from 'app/settings/createRelayEnvironment';
import Salutation from 'app/components/dashboard/includes/Salutation';
const DashboardQuery = graphql`
query DashboardQuery {
viewer {
...Salutation_viewer
}
}
`;
class Dashboard extends Component {
render() {
return (
<QueryRenderer
environment={environment}
query={DashboardQuery}
render={({error, props}) => {
if (error) {
return <div>{error.message}</div>;
} else if (props) {
return (
<div>
<Salutation viewer={props.viewer}></Salutation>
</div>
);
}
return <div>Loading</div>;
}}
/>
);
}
}
export default Dashboard;
The Salutation-component:
import React, {Component} from 'react';
import {createFragmentContainer, graphql} from 'react-relay';
import PropTypes from 'prop-types';
import UpdateDashboardMutation from 'app/mutations/UpdateDashboardMutation';
class Salutation extends Component {
render() {
return (
<div className="salutation">
<h2>Willkommen {this.props.viewer.firstName}</h2>
<input type="text" onChange={this._onChange.bind(this)}/>
</div>
);
}
_onChange(event) {
UpdateDashboardMutation(event.currentTarget.value);
}
}
Salutation.propTypes = {
viewer: PropTypes.object
};
export default createFragmentContainer(Salutation, graphql`
fragment Salutation_viewer on Viewer {
firstName
}
`);
And the Updatemutation:
import {commitMutation, graphql} from 'react-relay';
import environment from 'app/settings/createRelayEnvironment';
const mutation = graphql`
mutation UpdateDashboardMutation($input: UpdateDashboardMutationInput!) {
updateDashboard(input: $input) {
ok,
errors {
field,
messages
}
}
}
`;
function UpdateDashboardMutation(firstName) {
commitMutation(
environment,
{
mutation,
variables: {
input: {
firstName
}
},
updater(store) {
// what i have to do here?
}
}
);
}
export default UpdateDashboardMutation;
Try:
const viewer = store.getRootField('viewer');
viewer.setValue(firstName, 'name');
See https://facebook.github.io/relay/docs/en/relay-store for details.

How to import from the database a list of companies in the live search?

import css from './SearchField.styl';
import React, { Component } from 'react';
import CN from 'classnames';
import CompanyList from 'Company/List/CompanyList';
import Autosuggest from 'react-autosuggest';
const suburbs = ['Cheltenham', 'Mill Park', 'Mordialloc', 'Nunawading'];
export default class SearchInput extends Component {
render() {
function getSuggestions(input, callback) {
const regex = new RegExp('^' + input, 'i');
const suggestions = suburbs.filter(suburb => regex.test(suburb));
setTimeout(() => callback(null, suggestions), 300); // Emulate API call
}
return (
<div className={CN(css.selectLive)}>
<Autosuggest suggestions={getSuggestions} />
</div>
);
}
};
I have a list of companies , a component
How do I connect to the live search ? I am new and it is impossible to connect the data from the database

Resources