Full row editing with custom select editor and dynamic options updating - reactjs

I am trying to implement a custom select editor with dynamic options updating in ag-grid.
Saw an example of the same in vue js
AG Grid Vue example
How can to render the dynamic options in table cell?
//custom dropdown for cell editor
export const CustomDropDownEditor = forwardRef((props: any, ref) => {
const createInitialState = () => {
let startValue = props.value;
const filter = props?.values?.filter((item) => item.isSelected);
if (filter?.length) {
startValue = filter[0].dataFieldLookupId;
} else {
startValue = -1;
}
return {
value: startValue,
};
};
const [value, setValue] = useState(-1);
const refSelect = useRef<HTMLSelectElement>(null);
const dispatch = useDispatch<any>();
useEffect(() => {
if (props?.values?.length) {
const state: any = createInitialState();
setValue(state.value);
}
}, [props]);
useImperativeHandle(ref, () => {
return {
getValue() {
return value;
},
isCancelBeforeStart() {
},
isCancelAfterEnd() {
},
};
});
const onselectionchange = (e) => {console.log(props)
if (props?.properties?.dataFieldRelation) {
let service: any = props?.properties?.dataFieldRelation?.subSetValueService;
if (service !== undefined) {
service = service.replace("{dataFieldLookupId}", e?.target?.value);
dispatch(getDatafieldValues(service, props?.properties?.dataFieldRelation?.childDataFieldId, props.body))
}
const index = props?.datafields?.findIndex((item) => item?.uniqueDataFieldId == props?.properties?.uniqueDataFieldId);
props?.datafields[index]?.validatedValues?.forEach(element => {
if (element?.dataFieldLookupId == e.target.value)
element.isSelected = true;
else
element.isSelected = false;
});
props?.setFields(props?.datafields);
} else {
if (props?.properties?.dataFieldName === "Test Method") {
} else if (props?.properties?.dataFieldName === "Test Result") {
} else {
const index = props?.datafields?.findIndex((item) => item?.uniqueDataFieldId == props?.properties?.uniqueDataFieldId);
props?.datafields[index]?.validatedValues?.forEach(element => {
if (element?.dataFieldLookupId == e.target.value)
element.isSelected = true;
else
element.isSelected = false;
});
props?.setFields(props?.datafields);
}
}
setValue(e.target.value);
}
return (
<select
ref={refSelect}
name={props.properties.uniqueDataFieldId}
id={props.properties.uniqueDataFieldId}
value={value}
onChange={onselectionchange}>
<option value={-1}>--Select--</option>
{props?.values?.map((item, key) => (
<option key={key} value={item.dataFieldLookupId}>{item.dataFieldLookupValue}</option>
))
}
</select>
)
})
//get column definition in dynamically
const getEquipmentColumn = (generalProperties, datafields, isEditMode) => {
const columnInfo: any = [];
if (generalProperties?.length) {
for (var i = 0; i < generalProperties?.length; i++) {
if (generalProperties[i]?.name === "EquipmentId") {
let data: any = {
headerName: "action",
minWidth: 150,
cellRenderer: EditButtom,
editable: false,
colId: "action",
pinned: "left",
lockPinned: true
}
columnInfo.push(data);
}
if (generalProperties[i]?.propertyType !== "INTERNAL") {
let data: any = {
headerName: generalProperties[i]?.alias,
field: generalProperties[i]?.name,
comparator: comparator,
}
if (datafields?.length && isEditMode) {
const filterData = datafields?.filter((item) => item?.uniqueDataFieldId === generalProperties[i]?.uniqueDataFieldId);
if (filterData?.length) {
if (["Text Box", "Text Area"].includes(filterData[0]?.dataEntryControl?.dataEntryControlName)) {
if (filterData[0].disabled === false) {
data.editable = true;
data.cellEditor = "customeTextBox"
data.cellEditorParams = {
properties: filterData[0],
datafields: datafields,
}
} else {
data.editable = false;
}
}
else if (filterData[0]?.dataEntryControl?.dataEntryControlName === "Date Picker") {
data.editable = false;
} else if (filterData[0]?.dataEntryControl?.dataEntryControlName === "Date Time Picker") {
data.editable = false;
} else if (filterData[0]?.dataEntryControl?.dataEntryControlName === "Drop-down list") {
if (filterData[0].disabled === false) {
data.editable = true;
data.cellEditor = "customDropDown"
data.cellEditorParams = {
values: filterData[0].validatedValues,
properties: filterData[0],
datafields: datafields,
body: body,
setFields: (props) => setDatafields([...props]),
}
} else {
data.editable = false;
}
}
} else {
data.editable = false;
}
}
columnInfo.push(data);
}
}
}
return [columnInfo, isEditMode];
}
//getting additional values for dependency dropdown
useLayoutEffect(() => {
if (additionalFieldValues) {
let fieldValues = JSON.parse(JSON.stringify(additionalFieldValues));
const findIndex = datafields?.findIndex((item) => item.uniqueDataFieldId === fieldValues[1]);
if (findIndex >= 0) {
datafields[findIndex].validatedValues = fieldValues[0];
}
agGridRef.current.api.refreshCells({ columns: [`${datafields[findIndex].dataFieldName}`], force: true });
setDatafields(datafields);
dispatch(setAdditionalDatafieldValues(""));
}
}, [additionalFieldValues])

Related

Why my const var is empty but the related filter works

RemoveArea(area: models.Area) {
let messages: string[] = [];
messages = messages.concat(this.getMessagesFromDeletingArea(area));
this._translate.get('QuestionGroup_RemoveAreaConfirm',
{ thisCaption: area.caption[this.BlueContext.currentLanguage] }).subscribe(nextCaption => {
this.dialogsService.confirm(nextCaption, messages)
.subscribe(confirmed => {
if (confirmed) {
this._areaService.removeArea(this.dashboardConfiguration, area, this.BlueContext.currentLanguage);
const index = this.areas.findIndex(a => a.id === area.id);
if (index > -1) {
this.areas.splice(index, 1);
//here
this.dashboardConfiguration.widgets.forEach(wAId => {
const allWidgetByAreaId = wAId.widgets.filter(w => w.areaId === area.id);
allWidgetByAreaId.forEach(w => {
w.areaId = null;
});
});
}
}
});
});
}
The filter is working but the const var (allWidgetByAreaId) is undefined and empty so "for each " does not work. Would you please help?

react-beautiful-dnd: Prevent flicker when drag and drop a lists with API call

I'm using this react-beautiful-dnd library to be able to reorder lists. However, even though I'm able to drag and drop and re-order, there is a flicker when I try to move a card from one list to another list I call API when a card is dragged to the destination list
const onDragEnd = (result: any) => {
if (!result.destination) {
return;
}
const listCopy: any = { ...elements };
const sourceList = listCopy[result.source.droppableId];
const [removedElement, newSourceList] = removeFromList(
sourceList,
result.source.index
);
listCopy[result.source.droppableId] = newSourceList;
const destinationList = listCopy[result.destination.droppableId];
listCopy[result.destination.droppableId] = addToList(
result.destination.droppableId,
destinationList || [],
result.destination.index,
removedElement,
result.source.droppableId
);
setElements(listCopy)};
and in addToList function I am calling API to update order on server
const addToList = (
changedList: string,
list: any[],
index: number,
element: any,
currentListId: string
) => {
let cardOrder;
const result = Array.from(list);
result.splice(index, 0, element);
const cardCurrentIndex = result.findIndex((item) => item.id === element.id);
if (list.length === 0) {
cardOrder = DEFAULT_PIPELINE_ORDER;
} else if (cardCurrentIndex === 0 && result.length !== 0) {
const nextCardOrder = result[1];
cardOrder = nextCardOrder.current_stage_order - STAGE_INCREMENT_AMOUNT;
} else if (cardCurrentIndex === result.length - 1) {
const nextCardOrder = result[result.length - 2];
cardOrder = nextCardOrder.current_stage_order + STAGE_INCREMENT_AMOUNT;
} else if (
Boolean(result[cardCurrentIndex - 1]) &&
Boolean(result[cardCurrentIndex + 1])
) {
cardOrder = Math.round(
(result[cardCurrentIndex - 1].current_stage_order +
result[cardCurrentIndex + 1].current_stage_order) /
2
);
}
let candidatesData: any = elements;
if (candidatesData) {
if (currentListId === changedList) {
candidatesData[changedList as any] = result as unknown as elementsType;
setElements([...candidatesData]);
} else {
candidatesData[currentListId as any] = candidatesData[
currentListId as any
]?.filter((item: any) => item.id !== element.id);
candidatesData[changedList as any] = result as unknown as elementsType;
setElements([...candidatesData]);
console.log("[...candidatesData]", [...candidatesData]);
}
}
const stageId = stagePipeLineLanes?.find(
(item) => item.id.toString() === changedList.toLowerCase()
)?.id;
if (
changedList === "applied" ||
changedList === "sourcing" ||
changedList === "interviewing"
) {
const changedDestination = changedList;
const destinationStages = positionDetails?.candidate_stages.filter(
(item) =>
item.pipeline.toLowerCase() === changedDestination.toLowerCase()
);
const stage = destinationStages.find((item) => item.is_default === true);
mutate(
{
candidateId: element.id.toString(),
data: compressObject({
stage: stage?.id.toString(),
}),
},
{
onSuccess: (response) => {
if (response) {
toast.success(
`Candidate moved to ${capitalizeFirstLetter(
changedDestination
)}`
);
}
},
}
);
} else {
mutate({
candidateId: element.id.toString(),
data: compressObject({
stage: stageId?.toString() || "",
current_stage_order: cardOrder?.toString() || "",
}),
});
}
return result;
};

React Native - SetTimeout() is not working. t.apply is not a function

I'm trying to play back audio after a delay of time
_onPlayPausePressed = () => {
if (this.sound != null) {
if (this.state.isPlaying) {
this.sound.pauseAsync();
} else {
setTimeout(this.sound.playAsync(), 2000);
}
}
};
However it returns error: t.apply is not a function. (In't.apply(void 0,o)','t.apply' is undefined)
I tried the updated method of Oleg. It worked the first time but it won't run again after that. Here are more insight of my code:
//import the array with sound details:{id, name desc, sound}
import { soundArray } from "./CreateRecord";
...
export default class CurrentRecord extends React.Component {
constructor(props) {
super(props);
this.currentSound = [];
this.recording = null;
this.sound = null;
this.isSeeking = false;
this.shouldPlayAtEndOfSeek = false;
this.state = {
haveRecordingPermissions: false,
isLoading: false,
isPlaybackAllowed: false,
muted: false,
soundPosition: null,
soundDuration: null,
recordingDuration: null,
shouldPlay: false,
isPlaying: false,
isRecording: false,
fontLoaded: false,
shouldCorrectPitch: true,
volume: 1.0,
rate: 1.0,
isModalVisible: false
};
this.recordingSettings = JSON.parse(
JSON.stringify(Audio.RECORDING_OPTIONS_PRESET_LOW_QUALITY)
);
}
//load the audio when the component mount
componentDidMount() {
this.loadAudio();
(async () => {
await Font.loadAsync({
"cutive-mono-regular": require("../../assets/fonts/CutiveMono-Regular.ttf")
});
this.setState({ fontLoaded: true });
})();
this._askForPermissions();
}
//load the sound
async loadAudio() {
const { navigation } = this.props;
const id = navigation.getParam("id");
this.sound = new Audio.Sound();
for (let i = 0; i < soundArray.length; i++) {
if (soundArray[i].id === id) {
this.currentSound = soundArray[i];
console.log(this.currentSound);
break;
}
}
try {
await this.sound.loadAsync({
uri: this.currentSound.sound /* url for your audio file */
});
await this.sound.setOnPlaybackStatusUpdate(
this._updateScreenForSoundStatus
);
} catch (e) {
console.log("ERROR Loading Audio", e);
}
}
//change screen based on the status
_updateScreenForSoundStatus = status => {
if (status.isLoaded) {
this.setState({
soundDuration: status.durationMillis,
soundPosition: status.positionMillis,
shouldPlay: status.shouldPlay,
isPlaying: status.isPlaying,
rate: status.rate,
muted: status.isMuted,
volume: status.volume,
shouldCorrectPitch: status.shouldCorrectPitch,
isPlaybackAllowed: true
});
} else {
this.setState({
soundDuration: null,
soundPosition: null,
isPlaybackAllowed: false
});
if (status.error) {
console.log(`FATAL PLAYER ERROR: ${status.error}`);
}
}
};
_askForPermissions = async () => {
const response = await Permissions.askAsync(Permissions.AUDIO_RECORDING);
this.setState({
haveRecordingPermissions: response.status === "granted"
});
};
//here's where i want to delay the audio file.
_onPlayPausePressed = () => {
if (this.sound != null) {
if (this.state.isPlaying) {
this.sound.pauseAsync();
} else {
setTimeout(() => this.sound.playAsync(), 2000);
}
}
};
_onStopPressed = () => {
if (this.sound != null) {
this.sound.stopAsync();
}
};
_onMutePressed = () => {
if (this.sound != null) {
this.sound.setIsMutedAsync(!this.state.muted);
}
};
_onVolumeSliderValueChange = value => {
if (this.sound != null) {
this.sound.setVolumeAsync(value);
}
};
_trySetRate = async (rate, shouldCorrectPitch) => {
if (this.sound != null) {
try {
await this.sound.setRateAsync(rate, shouldCorrectPitch);
} catch (error) {
// Rate changing could not be performed, possibly because the client's Android API is too old.
}
}
};
_onRateSliderSlidingComplete = async value => {
this._trySetRate(value * RATE_SCALE, this.state.shouldCorrectPitch);
};
_onPitchCorrectionPressed = async value => {
this._trySetRate(this.state.rate, !this.state.shouldCorrectPitch);
};
_onSeekSliderValueChange = value => {
if (this.sound != null && !this.isSeeking) {
this.isSeeking = true;
this.shouldPlayAtEndOfSeek = this.state.shouldPlay;
this.sound.pauseAsync();
}
};
_onSeekSliderSlidingComplete = async value => {
if (this.sound != null) {
this.isSeeking = false;
const seekPosition = value * this.state.soundDuration;
if (this.shouldPlayAtEndOfSeek) {
this.sound.playFromPositionAsync(seekPosition);
} else {
this.sound.setPositionAsync(seekPosition);
}
}
};
_getSeekSliderPosition() {
if (
this.sound != null &&
this.state.soundPosition != null &&
this.state.soundDuration != null
) {
return this.state.soundPosition / this.state.soundDuration;
}
return 0;
}
_getMMSSFromMillis(millis) {
const totalSeconds = millis / 1000;
const seconds = Math.floor(totalSeconds % 60);
const minutes = Math.floor(totalSeconds / 60);
const padWithZero = number => {
const string = number.toString();
if (number < 10) {
return "0" + string;
}
return string;
};
return padWithZero(minutes) + ":" + padWithZero(seconds);
}
_getPlaybackTimestamp() {
if (
this.sound != null &&
this.state.soundPosition != null &&
this.state.soundDuration != null
) {
return `${this._getMMSSFromMillis(
this.state.soundPosition
)} / ${this._getMMSSFromMillis(this.state.soundDuration)}`;
}
return "";
}
_getRecordingTimestamp() {
if (this.state.recordingDuration != null) {
return `${this._getMMSSFromMillis(this.state.recordingDuration)}`;
}
return `${this._getMMSSFromMillis(0)}`;
}
Change to
_onPlayPausePressed = () => {
if (this.sound != null) {
if (this.state.isPlaying) {
this.sound.pauseAsync();
} else {
setTimeout(()=>this.sound.playAsync(), 2000);
}
}
};
Remove execution of function. Also use arrow function(()=> {}) in playAsync
_onPlayPausePressed = async () => {
if (this.sound != null) {
if (this.state.isPlaying) {
await this.sound.pauseAsync();
} else {
setTimeout(() => {
await this.sound.playAsync()
}, 2000);
}
}
};

Mutable version of the filter function to filter results in React?

I have a function called renderExercises which I call in my render function. renderExercises returns an array of ExercisesChoose components.
renderExercises() {
const {selectedType} = this.state;
const allExercises = this.props.exercises;
let exercisesToRender = [];
if (selectedType !== 'all') {
exercisesToRender = allExercises[selectedType];
} else {
exercisesToRender = Object.values(allExercises)
.reduce((array, subarray) => array.concat(subarray), [])
.sort();
}
return exercisesToRender.map((exercise) => {
return (
<ExercisesChoose
key={exercise}
name={exercise}
/>
)
})
}
So far this works. However I also want to filter based on search text if the user has entered this text.
This isn't working as filter can't be called on the existing array exercisesToRender.
if (typeof this.searchText !== 'undefined') {
const searchText = this.searchText.value;
// This is not working
exercisesToRender.filter(item => {
return item.includes(searchText);
});
}
What is the solution to this? Is there a sort method that allows for mutation? If so, is this advisable to use?
This is my current solution which works but is pretty ugly:
renderExercises() {
const {selectedType} = this.state;
const allExercises = this.props.exercises;
let exercisesToRender = [];
if (selectedType !== 'all') {
exercisesToRender = allExercises[selectedType];
} else {
// Combine all the different exercise groups into a single array
exercisesToRender = Object.values(allExercises)
.reduce((array, subarray) => array.concat(subarray), [])
.sort();
}
let render = [];
if (typeof this.searchText !== 'undefined') {
const searchText = this.searchText.value;
render = exercisesToRender.filter(item => {
return item.includes(searchText);
});
} else {
render = exercisesToRender;
}
return render.map((exercise) => {
return (
<ExercisesChoose
key={exercise}
name={exercise}
/>
)
})
}
This is what my exercises object looks like:
this.props.exercises = [
legs:["Squat", "Power squats", "Burpees"]
pull:["Pull up", "Chin up", "Dumbbell curl", "Horizontal row"]
push:["Push up", "Bench press", "Dumbbell bench press", "Mountain climbers"]
cardio: ["Running high knees", "Plank", "Crunches", "Skipping"]
]
My strategy for this case would be:
reduce to filter exercises by type
filter them by searchText
sort
map to render
Final result:
renderExercises() {
const { selectedType } = this.state
const { exercises: allExercises } = this.props
return Object
.keys(allExercises)
.reduce((result, key) => {
if (selectedType === 'all' || key === selectedType) {
return [
...result,
...allExercises[key],
]
}
return result
}, [])
.filter(exercise => searchText ? exercise.includes(searchText) : true)
.sort()
.map(exercise =>
<ExercisesChoose
key={exercise}
name={exercise}
/>
)
}
const exercises = {
legs:["Squat", "Power squats", "Burpees"],
pull:["Pull up", "Chin up", "Dumbbell curl", "Horizontal row"],
push:["Push up", "Bench press", "Dumbbell bench press", "Mountain climbers"],
cardio: ["Running high knees", "Plank", "Crunches", "Skipping"],
}
const filterExercises = (type, searchText) => {
return Object
.keys(exercises)
.reduce((result, key) => {
if (type === 'all' || key === type) {
return [
...result,
...exercises[key],
]
}
return result
}, [])
.filter(exercise => searchText ? exercise.includes(searchText) : true)
.sort()
.join(', ')
}
console.log('All exercises:', filterExercises('all', ''))
console.log('All (up):', filterExercises('all', 'up'))
console.log('Push:', filterExercises('push', ''))
console.log('Push (press):', filterExercises('push', 'press'))
Ive expanded slightly on mersocarlin's answer as I was getting some false results from searchText, but essentially his logic does work.
renderExercises() {
const {selectedType} = this.state;
const allExercises = this.props.exercises;
let searchText = false;
if (this.searchText && this.searchText.value.length > 0) {
searchText = this.searchText.value.toLowerCase();
}
return Object
.keys(allExercises)
.reduce((result, key) => {
if (selectedType === 'all' || key === selectedType) {
return [
...result,
...allExercises[key]
]
}
return result
}, [])
.filter(exercise => searchText ? exercise.toLowerCase().includes(searchText) : true)
.map((exercise) => {
let active = false;
if (this.props.chosenExercise === exercise) {
active = true;
}
return (
<ExercisesChoose
key={exercise}
name={exercise}
active={active}
setNumber={this.props.number}
updateValue={this.props.updateValue}
/>
)
})
}

how to implement react tag input control with auto suggest code in JSX?

I am trying to implement the Auto suggest input with taggedit control available from the following link
https://github.com/olahol/react-tagsinput#example
i have tried my best and converted the code to Jsx format following below
'use strict';
/*LIBRARIES*/
var React = require('react');
var ReactDOM = require('react-dom');
var TagsInput = require('react-tagsinput');
var TagCss = require('react-tagsinput/react-tagsinput.css')
//var CustomScroll = require('react-custom-scroll');
//var CustomScrollCSS = require('react-custom-scroll/src/main/customScroll.css');
var ReactAutoSuggest = require('react-autosuggest');
var ReactAutoSize = require('react-input-autosize');
var TaggedInput = React.createClass({
getInitialState: function() {
return ({
tags: []
});
},
handleChange(tags) {
this.setState({
tags
});
},
states: function() {
return ([{
abbr: "AL",
name: "Alabama"
}, {
abbr: "AK",
name: "Alaska"
}, {
abbr: "AZ",
name: "Arizona"
}]);
},
render: function() {
const autocompleteRenderInput = (props) => {
const addTag = props;
const handleOnChange = (e, method) => {
if (method === 'enter') {
e.preventDefault();
} else {
props.onChange(e);
}
}
console.log(this.states());
const inputValue = (props.value && props.value.trim().toLowerCase()) || ""
const inputLength = inputValue.length
var tags = this.state;
var suggestions = this.states().filter((state) => {
return state.name.toLowerCase().slice(0, inputLength) === inputValue
});
var onSuggestionSelected = function(event, suggestion) {
props.addTag(suggestion.name);
}
var shouldRenderSuggestions = function(value) {
return value.trim().length > 2;
}
var getSuggestionValue = function(suggestion) {
return suggestion.name;
}
var renderSuggestion = function(suggestion) {
return <span > {
suggestion.name
} < /span>;
}
const inputProps = {
value, // usually comes from the application state
handleOnChange, // called every time the input value changes
onBlur, // called when the input field loses focus, e.g. when user presses Tab
type: 'search',
placeholder: 'Enter city or postcode'
};
return ( <
ReactAutoSuggest ref = {
props.ref
}
suggestions = {
suggestions
}
shouldRenderSuggestions = {
shouldRenderSuggestions
}
getSuggestionValue = {
getSuggestionValue
}
renderSuggestion = {
renderSuggestion
}
inputProps = {
inputProps
} > < /ReactAutoSuggest>)
}
return ( < TagsInput renderInput = {
autocompleteRenderInput
}
value = {
this.state.tags
}
onChange = {
this.handleChange
}
/>);
}
});
ReactDOM.render( < TaggedInput / > , document.getElementById('divSharedLeadContainer'));
and not able to bring the output.
It would be very helpful someone can give the samples in JSX code.

Resources