Select all checkbox redux form - material-ui

I want to check/ uncheck all checkboxes the moment I select Check All but can't make it work. I'm using material-ui components and redux-form. my plan is to grab checkAll field value using formValueSelector API and set checkbox A and B value based of that. Also tried using value prop but no luck still.
import React from 'react';
import { connect } from 'react-redux';
import { Field, reduxForm, formValueSelector } from 'redux-form';
import { Checkbox } from 'redux-form-material-ui';
let Form = (props) => {
return (
<form>
<Field name="checkAll" id="checkAll" label="Check All" component={ Checkbox } />
<Field name="a" label="A" component={ Checkbox } checked={ props.checkAll } />
<Field name="b" label="B" component={ Checkbox } checked={ props.checkAll } />
</form>
);
};
Form = reduxForm({
form: 'Form'
})(AddReturnModal);
// Decorate with connect to read form values
const selector = formValueSelector('Form'); // <-- same as form name
Form = connect(
(state) => {
const checkAll = selector(state, 'checkAll');
return {
checkAll
};
}
)(Form);
export default Form;

You could use change method. From docs:
change(field:String, value:any) : Function
Changes the value of a field in the Redux store. This is a bound action creator, so it returns nothing.
The only solution I see is to loop over the list of checkboxes and call change(checkboxName, value) on them.

#notgiorgi is right, to select all checkboxes, you can do this:
selectAll = () => {
const { change } = this.props
['a', 'b'].forEach((field) => change(field, true))
}
If you wanted a toggle, you might easily/cheaply/ignorantly be able to keep a rough reference to the selectAll state:
selectAllValue = false
selectAll = () => {
const { change } = this.props
['a', 'b'].forEach((field) => change(field, this.selectAllValue))
// toggle select all to select none
this.selectAllValue = !this.selectAllValue
}

Related

Material UI select dropdown arrow keys navigation not working

I added a textfield inside mui multiple select component , now keyboard arrow up and down list navigation is not working instead,on arrow onkeydown it focuses on the div itself (scrolling on arrow keydown).
Any help is appreciated (AutoComplete is not an option)
Have tried adding autoFocus on MenuItem itself , but that starts from the last list
import * as React from "react";
import { Theme, useTheme } from "#mui/material/styles";
import MenuItem from "#mui/material/MenuItem";
import TextField from "#mui/material/TextField";
import FormControl from "#mui/material/FormControl";
import Select, { SelectChangeEvent } from "#mui/material/Select";
const ITEM_HEIGHT = 48;
const ITEM_PADDING_TOP = 8;
const MenuProps = {
PaperProps: {
style: {
maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
width: 250
}
}
};
const names = [
"Oliver Hansen",
"Van Henry",
"April Tucker",
"Ralph Hubbard",
"Omar Alexander",
"Carlos Abbott",
"Miriam Wagner",
"Bradley Wilkerson",
"Virginia Andrews",
"Kelly Snyder"
];
function getStyles(name: string, personName: string[], theme: Theme) {
return {
fontWeight:
personName.indexOf(name) === -1
? theme.typography.fontWeightRegular
: theme.typography.fontWeightMedium
};
}
export default function MultipleSelect() {
const theme = useTheme();
const [personName, setPersonName] = React.useState<string[]>([]);
const handleChange = (event: SelectChangeEvent<typeof personName>) => {
const {
target: { value }
} = event;
setPersonName(
// On autofill we get a stringified value.
typeof value === "string" ? value.split(",") : value
);
};
return (
<div>
<FormControl sx={{ m: 1, width: 300 }}>
<Select
multiple
value={personName}
onChange={handleChange}
MenuProps={MenuProps}
onKeyDown={(e) => {
if (e.key !== "Escape") {
e.stopPropagation();
}
}}
>
<div style={{ textAlign: "center", margin: "20px 0px" }}>
<TextField placeholder="type..." />
</div>
{names.map((name) => (
<MenuItem
key={name}
value={name}
style={getStyles(name, personName, theme)}
>
{name}
</MenuItem>
))}
</Select>
</FormControl>
</div>
);
}
It seems the issue is that the TextField element is a child of the Select element and is intercepting the keydown events that would normally be used to navigate the list of options. One way to fix this would be to use the onKeyDown prop on the TextField element to prevent it from intercepting the keydown events. Instead of calling e.stopPropagation(), you can call e.preventDefault() which will prevent the event from being handled by the TextField element and allow it to be handled by the Select element.
<TextField placeholder="type..." onKeyDown={e => e.preventDefault()}/>
Also to make sure that focus is on the first element in the list after the user opens the list you can use autoFocus prop on the first element of the list.
<MenuItem
key={names[0]}
value={names[0]}
style={getStyles(names[0], personName, theme)}
autoFocus
>
{names[0]}
</MenuItem>
This should allow the arrow keys to navigate the list as expected, while still allowing the user to type into the TextField.

Fire datatable event based on cutom lookup record selection in salesforce LWC

I have custom reusablelookup component, datatable component. If and only if I select some record in lookup, only corresponding results must be displayed in datatable. If no record is selected in lookup, datatable should display 0 records.(I am struck here "how to fire event from one to other or connecting these both components")
I have used reusable lookup component from here..https://www.sfdcpanther.com/custom-lookup-in-lightning-web-component/
Datatable JS
#wire(getProvider)
wireddata({ error, data }){
if (data)
{ var ObjData = JSON.parse(JSON.stringify(data));
ObjData.forEach(record => {
record.AccountName = record.ProviderId__r != undefined ? record.ProviderId__r.Name:'';
record.AccountPhone = record.ProviderId__r != undefined ? record.ProviderId__r.NPI__c: '';
record.AccountManager = record.ProviderId__r != undefined ? record.ProviderId__r.FedId__c: '';
record.AccountAddress1 = record.ProviderId__r != undefined ? record.ProviderId__r.LicenceId__c: '';
record.AccountAddress2 = record.ProviderId__r != undefined ? record.ProviderId__r.MedicareOscarNumber__c: '';
});
//alert('After====> '+ JSON.stringify(ObjData));
this.allRecords = ObjData;
this.showTable = true;
}
else if (error) {
this.error = error;
this.data = undefined;
}
}
Datatable HTML
<template if:true={showTable}>
<c-lwc-datatable-utility records={allRecords}
total-records={allRecords.length}
columns = {columns}
key-field="Id"
show-search-box="true"
onrowaction={handleRowAction}
onpaginatorchange={handlePaginatorChange}
table-height="200">
</c-lwc-datatable-utility>
</template>
Lookup JS
fields = ["Provider_Name_API__c","NPI__c","FedId__c"];
displayFields = 'Provider_Name_API__c, NPI__c, FedId__c'
handleLookup(event){
console.log( JSON.stringify ( event.detail) )
}
lookup HTML
<p class="slds-p-horizontal_small">
<c-search-component
obj-name="ProviderEntity__c"
icon-name="standard:contact"
label-name="Provider Search"
placeholder="Search"
fields={fields}
display-fields={displayFields}
onlookup={handleLookup}
onchange={handleChange} >
</c-search-component>
</p>
So you have two independent components: a DataTable component and a LookUp Component. Based on a value that will be selected in the LookUp component, the DataTable should react and display some rows.
Because the two components are independent, you have two ways of communicating both components:
Using the Lightning Message Service (more info here https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.use_message_channel). You should create a new channel to which your DataTable component would subscribe. The LookUp component should publish some event to the Channel when the value is selected and the DataTable component would receive it and react accordingly
The second way to achieve the communication would be to create a parent component that would contain both components (the DataTable one and the LookUp one). Then, the parent component would listen to a CustomEvent fired by the LookupElement (https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.events_create_dispatch) and then react accordingly (maybe changing some parameter on the table or even just changing the "records" attribute). As an example, I've created some components that display the idea. I have not used exactly your lookup to simplify but the idea for the communication would be the same. In my case, the "c-custom-picklist" is acting as your Lookup component and the "c-custom-text-area" is acting as your DataTable Component. c-parent-component communicates both components:
Parent Component HTML:
<template>
<c-custom-picklist oncolor={handleColorChange}></c-custom-picklist>
<c-custom-text-area selected-color={selectedColor}></c-custom-text-area>
</template>
Parent Component JS:
import { LightningElement } from "lwc";
export default class ParentComponent extends LightningElement {
selectedColor = "No Color Selected";
handleColorChange(event) {
this.selectedColor = event.detail;
}
}
Picklist Component HTML:
<template>
<lightning-combobox
label="Select a Color"
placeholder="Select a Color"
options={options}
onchange={handleChange}
></lightning-combobox>
</template>
Picklist component JS:
import { LightningElement } from "lwc";
export default class CustomPicklist extends LightningElement {
options = [
{ value: "Red", label: "Red" },
{ value: "Blue", label: "Blue" },
{ value: "Pink", label: "Pink" }
];
handleChange(event) {
let selectedColor = event.detail.value; //Selected Color
this.dispatchEvent(new CustomEvent("color", { detail: selectedColor }));
}
}
Text Area HTML:
<template>
<textarea>
The selected color is: {selectedColor}
</textarea
>
</template>
Text Area JS:
import { LightningElement, api } from "lwc";
export default class CustomTextArea extends LightningElement {
#api selectedColor;
}

Draftail mention plugin for wagtail

I would like to customise the draftail editor in wagtail in order to have "mentions" functionality (I am using the draft js plugin)
Because my react skills are extremely poor and my knowledge of draftail/draftjs very limited, I am using https://github.com/vixdigital/wagtail-plugin-base as a starting point (without knowing much about what it does) and trying to muddle through the task
I have managed to get it so the mention functionality appears in wagtail. The problem is that it appears in a "sub" editor in the toolbar
enter image description here
How can I avoid creating a sub editor and have it work in the body of the existing editor? Below are the two main JS files in my "wagtail-plugin-base"
index.js
import AutoComplete from './AutoComplete/AutoComplete.js';
window.draftail.registerControl(AutoComplete)
AutoComplete.js
import React, { Component } from '../../node_modules/react';
import createMentionPlugin, { defaultSuggestionsFilter } from '../../node_modules/draft-js-mention-plugin';
import editorStyles from './editorStyles.css';
import { mentions } from './mentions'
import { DraftailEditor, BLOCK_TYPE, INLINE_STYLE, createEditorState } from "draftail"
const mentionPlugin = createMentionPlugin();
const AutoComplete = class SimpleMentionEditor extends Component {
state = {
editorState: createEditorState,
suggestions: mentions,
};
onChange = (editorState) => {
this.setState({
editorState,
});
};
onSearchChange = ({ value }) => {
this.setState({
suggestions: defaultSuggestionsFilter(value, mentions),
});
};
onAddMention = () => {
// get the mention object selected
}
focus = () => {
this.editor.focus();
};
render() {
const { MentionSuggestions } = mentionPlugin
return (
<div>
<DraftailEditor
editorState={this.state.editorState}
onChange={this.onChange}
plugins={[mentionPlugin]}
ref={(element) => { this.editor = element; }}
/>
<MentionSuggestions
onSearchChange={this.onSearchChange}
suggestions={this.state.suggestions}
onAddMention={this.onAddMention}
/>
</div>
);
}
}
export default AutoComplete;
Any pointers much appreciated!

How to disable the SaveButton when the SimpleForm is invalid in a react-admin app?

In a react-admin SimpleForm component validation is working fine when I click the save button. The field that is required is highlighted and marked red when I click the save button.
I'd like to add a className to the SaveButton as long as the form is invalid. This way I can make it clear to the user that he's not done with the form yet and prevent the user from clicking it.
This is a simplified version of such a SimpleForm.
import {
required,
//...
} from 'react-admin';
const UserCreateToolbar = props =>
<Toolbar {...props}>
<SaveButton
label="user.action.save_and_show"
redirect="show"
submitOnEnter={true}
/>
</Toolbar>;
export const UserCreate = props =>
<Create {...props}>
<SimpleForm
toolbar={<UserCreateToolbar />}
>
<TextInput source="name" validate={[required()]} />
</SimpleForm>
</Create>;
You can create your own SaveButton component, connected to redux, which will get the validation status from the state (check the redux-form documentation) for the form which is always named record-form in react-admin.
Then, you can apply the disabled prop on the button and eventually tweak its styles
Here's my own SaveButton component I came up with. It's working for me. Thanks #Gildas for pointing me in the right direction.
import React from 'react';
import PropTypes from 'prop-types';
import { reduxForm } from 'redux-form';
import { SaveButton } from 'react-admin';
const SaveButtonAware = ({ invalid, ...rest }) => (
<SaveButton disabled={invalid} {...rest} />
);
SaveButtonAware.propTypes = {
invalid: PropTypes.bool,
};
export default reduxForm({
form: 'record-form',
})(SaveButtonAware);
Update. Apparently, this is working too. Not sure why.
import React from 'react';
import PropTypes from 'prop-types';
import { SaveButton } from 'react-admin';
const SaveButtonAware = ({ invalid, ...rest }) => (
<SaveButton disabled={invalid} {...rest} />
);
SaveButtonAware.propTypes = {
invalid: PropTypes.bool,
};
export default SaveButtonAware;
You should first create a customized toolbar and set Save button's disabled element to Toolbars invalid state, as shown below. ( Toolbar always have the state of form)
import * as React from "react";
import {
Toolbar,
SaveButton
} from 'react-admin';
const CustomToolbar = (props) => (
<Toolbar {...props}>
<SaveButton disabled={props.invalid}/>
</Toolbar>
);
export default CustomToolbar;
Then use this customized toolbar in your form like shown below:
<SimpleForm redirect="list" toolbar={<CustomToolbar/>}>
{your form elements}
</SimpleForm>

Handle selected event in autocomplete textbox using bootstrap Typeahead?

I want to run JavaScript function just after user select a value using autocomplete textbox bootstrap Typeahead.
I'm searching for something like selected event.
$('.typeahead').on('typeahead:selected', function(evt, item) {
// do what you want with the item here
})
$('.typeahead').typeahead({
updater: function(item) {
// do what you want with the item here
return item;
}
})
For an explanation of the way typeahead works for what you want to do here, taking the following code example:
HTML input field:
<input type="text" id="my-input-field" value="" />
JavaScript code block:
$('#my-input-field').typeahead({
source: function (query, process) {
return $.get('json-page.json', { query: query }, function (data) {
return process(data.options);
});
},
updater: function(item) {
myOwnFunction(item);
var $fld = $('#my-input-field');
return item;
}
})
Explanation:
Your input field is set as a typeahead field with the first line: $('#my-input-field').typeahead(
When text is entered, it fires the source: option to fetch the JSON list and display it to the user.
If a user clicks an item (or selects it with the cursor keys and enter), it then runs the updater: option. Note that it hasn't yet updated the text field with the selected value.
You can grab the selected item using the item variable and do what you want with it, e.g. myOwnFunction(item).
I've included an example of creating a reference to the input field itself $fld, in case you want to do something with it. Note that you can't reference the field using $(this).
You must then include the line return item; within the updater: option so the input field is actually updated with the item variable.
first time i've posted an answer on here (plenty of times I've found an answer here though), so here's my contribution, hope it helps. You should be able to detect a change - try this:
function bob(result) {
alert('hi bob, you typed: '+ result);
}
$('#myTypeAhead').change(function(){
var result = $(this).val()
//call your function here
bob(result);
});
According to their documentation, the proper way of handling selected event is by using this event handler:
$('#selector').on('typeahead:select', function(evt, item) {
console.log(evt)
console.log(item)
// Your Code Here
})
What worked for me is below:
$('#someinput').typeahead({
source: ['test1', 'test2'],
afterSelect: function (item) {
// do what is needed with item
//and then, for example ,focus on some other control
$("#someelementID").focus();
}
});
I created an extension that includes that feature.
https://github.com/tcrosen/twitter-bootstrap-typeahead
source: function (query, process) {
return $.get(
url,
{ query: query },
function (data) {
limit: 10,
data = $.parseJSON(data);
return process(data);
}
);
},
afterSelect: function(item) {
$("#divId").val(item.id);
$("#divId").val(item.name);
}
Fully working example with some tricks. Assuming you are searching for trademarks and you want to get the selected trademark Id.
In your view MVC,
#Html.TextBoxFor(model => model.TrademarkName, new { id = "txtTrademarkName", #class = "form-control",
autocomplete = "off", dataprovide = "typeahead" })
#Html.HiddenFor(model => model.TrademarkId, new { id = "hdnTrademarkId" })
Html
<input type="text" id="txtTrademarkName" autocomplete="off" dataprovide="typeahead" class="form-control" value="" maxlength="100" />
<input type="hidden" id="hdnTrademarkId" />
In your JQuery,
$(document).ready(function () {
var trademarksHashMap = {};
var lastTrademarkNameChosen = "";
$("#txtTrademarkName").typeahead({
source: function (queryValue, process) {
// Although you receive queryValue,
// but the value is not accurate in case of cutting (Ctrl + X) the text from the text box.
// So, get the value from the input itself.
queryValue = $("#txtTrademarkName").val();
queryValue = queryValue.trim();// Trim to ignore spaces.
// If no text is entered, set the hidden value of TrademarkId to null and return.
if (queryValue.length === 0) {
$("#hdnTrademarkId").val(null);
return 0;
}
// If the entered text is the last chosen text, no need to search again.
if (lastTrademarkNameChosen === queryValue) {
return 0;
}
// Set the trademarkId to null as the entered text, doesn't match anything.
$("#hdnTrademarkId").val(null);
var url = "/areaname/controllername/SearchTrademarks";
var params = { trademarkName: queryValue };
// Your get method should return a limited set (for example: 10 records) that starts with {{queryValue}}.
// Return a list (of length 10) of object {id, text}.
return $.get(url, params, function (data) {
// Keeps the current displayed items in popup.
var trademarks = [];
// Loop through and push to the array.
$.each(data, function (i, item) {
var itemToDisplay = item.text;
trademarksHashMap[itemToDisplay] = item;
trademarks.push(itemToDisplay);
});
// Process the details and the popup will be shown with the limited set of data returned.
process(trademarks);
});
},
updater: function (itemToDisplay) {
// The user selectes a value using the mouse, now get the trademark id by the selected text.
var selectedTrademarkId = parseInt(trademarksHashMap[itemToDisplay].value);
$("#hdnTrademarkId").val(selectedTrademarkId);
// Save the last chosen text to prevent searching if the text not changed.
lastTrademarkNameChosen = itemToDisplay;
// return the text to be displayed inside the textbox.
return itemToDisplay;
}
});
});