Below is the grid that I have developed using Kendo-Angular2.
I need a click event on the row and in the event I need the row information.
I wrote a general click event and tried o get the row information, but it doesn't work if I go to second page in the pagination. Is there a simple row click event that gives the row information.
plnkr:
http://plnkr.co/edit/h0fVaP4NykRiILA7dyHn?p=preview
click event code:
ngAfterViewInit() {
this.renderer.listen(this.gridRef.nativeElement, "mousedown", (event) => {
if (!event.target.matches('tbody>tr *')) {
return;
}
const gridData = this.grid.data;
const tr = event.target.closest('tr');
const dataItem = gridData.data[tr.rowIndex + this.grid.skip];
console.log(dataItem);
});
}
Angular Template
<kendo-grid #gridUser
[kendoGridBinding]="gridData"
[pageSize]="10"
[pageable]="true"
[sortable]="true"
[selectable]="true"
(selectionChange)="gridUserSelectionChange(gridUser, $event)">
<kendo-grid-column field="name" title="ID">
</kendo-grid-column>
<kendo-grid-column field="nameThai" title="Name">
</kendo-grid-column>
<kendo-grid-pdf fileName="User.pdf"></kendo-grid-pdf>
<kendo-grid-excel fileName="User.xlsx"></kendo-grid-excel>
</kendo-grid>
Angular Component
gridUserSelectionChange(gridUser, selection) {
// let selectedData = gridUser.data.data[selection.index];
const selectedData = selection.selectedRows[0].dataItem;
console.log(selectedData);
}
Related
I am using react and axios for frontend, and nextjs with prisma for backend. I have in the database 4000 exercices that contain fitness exercices. I want to create a function where by each key stroke, the api will look for the relevant exercice. I finished creating it, but i have some issues:
The main problem is that the response is delayed from the first keystrokes, because the payload response is tooo large. I created a scrollable UL element to render the elements, because I want to get also the Gif images. So the elements, if the API will find those, will be rendered on the screen.
If I add to each element an on click event, to select the exercice's Id, I get an error "too many re-rendering on the screen".
How can I optimise the function, and how can I solve the error of too many re-render on the screen? Nextjs tells me that it will create an infinite loop....
The frontend looks like this:
const [open, setOpen] = useState(false);
const [keyWord, setKeyWord] = useState('');
const [array, setArray] = useState([]);
const [exerciceId, setExerciceId] = useState('');
// Add exercice
const hadnleAddExercie = async event => {
event.preventDefault();
console.log('exercice added');
}
// Look for exercices
const searchExercices = async event => {
event.preventDefault();
setKeyWord(event.target.value);
const arrayExercices = await getExercicesByKeyWords(keyWord);
setArray(arrayExercices);
console.log(arrayExercices);
}
<div className='flex mt-3 flex-col'>
<input onChange={searchExercices} required placeholder='Search by word...' className='border border-slate-400 p-1 rounded-md flex-1 max-w-sm my-2'/>
<ul className='border border-slate-400 p-1 rounded-md max-w-sm my-2 max-h-52 overflow-scroll'>
{
array.length > 1 && array.map(exercice => (
<li key={exercice.id} className='flex flex-wrap p-2 bg-slate-200 m-2 items-center rounded-md'>
<span><Image className='rounded-xl mr-2' priority width={40} height={40} src={exercice.gifUrl} alt={exercice.name}/></span>
<span>{ exercice.name }</span>
</li>
))
}
</ul>
</div>
The backend Uses prisma and I use the OR clause to look for a word in different rows:
export default async function handler(req, res) {
try {
const param = req.query.slug[0];
console.log(param);
// Get exercices where the two rows contains a single parametter
const exercices = await prisma.exercices.findMany({
where: {
OR: [
{
name: {
contains: param
}
},
{
target: {
contains: param
}
},
{
equipment: {
contains: param
}
}
]
}
});
res.status(200).send(exercices);
}
catch (error) {
console.log(error);
res.status(500).send(error);
}
}
An example can be this:
Only for finding an exercice I used 500mb...
Here are a few ways I can think of to optimize this:
Use pagination and fetch more results as user scrolls down or actually separate it by using pages. You can read more on how to implement pagination in Prisma here.
Add debounce to your search term so it doesn't actually fire on every single keystroke, you could use something like useDebounce.
Use React.memo to prevent the list from being re-rendered every time some state changes, only re-render it when the actual list changes.
I'm building a trading application and using node on the server side and react on client side.The current issue which I'm facing is regarding react performance on very frequents updates.
My process is describe as below.
The most common case I have is two tables displaying option data call and put. Each table have min of two rows and max of 8, so in total we'll have max 16 rows at single time. Each row can have up to 30 columns.
For updating I'm using a socket connection. Whenever a simple change occur in any of option column occurs an event emits from socket server which I'll be listening on client side.
After getting the data on client side via socket I can search for the specific row and column that where to update the data then re build the whole data of all 16 rows using the old data and new data and then dispatch the action... this updates occurs very frequently like 100s of 1000s of updates per millisecond and because of which whole table got re rendered and causing my app slow down.
I'm using redux to manage state in my react application
Here is an example with pure components no problem updating about 100 times a second:
const { useState, memo, useEffect, useRef } = React;
const COLUMS = 31;
const ITEM_COUNT = COLUMS * COLUMS;
const TIMER = 10;
const COLORS = ['red', 'green', 'blue'];
const nextColor = ((current) => () =>
COLORS[++current % COLORS.length])(0);
const next = ((num) => () => ++num % ITEM_COUNT)(-1);
const Item = memo(function Item({ color }) {
return (
<td
style={{
border: '1px solid black',
minWidth: '20px',
minHeight: '20px',
backgroundColor: color,
transitionDuration: '2s',
transitionTimingFunction: 'ease-out',
transitionProperty: 'color, background-color',
}}
>
</td>
);
});
const Row = memo(function Row({ items }) {
return (
<tr>
{items.map((item) => (
<Item key={item.id} color={item.color} />
))}
</tr>
);
});
const App = () => {
const r = useRef(0);
r.current++;
const [data, setData] = useState(
new Array(ITEM_COUNT)
.fill('')
.map((_, id) => ({ id, color: 'red' }))
.reduce((result, item, index) => {
if (index % COLUMS === 0) {
result.push([]);
}
result[result.length - 1].push(item);
return result;
}, [])
);
useEffect(() => {
const i = setInterval(
() =>
setData((data) => {
const change = next(), //id to change
color = nextColor(); //new value for color
return data.map(
(items) =>
//do not update items if id is not in this row
items.find(({ id }) => id === change)
? //update the one item that has id of change
items.map(
(item) =>
item.id === change
? { ...item, color } //change the color
: item //return the item unchanged
)
: items //id is not in this row return items unchanged
);
}),
TIMER
);
return () => clearInterval(i);
}, []);
return (
<div>
<h1>rendered: {r.current}</h1>
<table>
<tbody>
{data.map((items, index) => (
<Row key={index} items={items} />
))}
</tbody>
</table>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I don't know why you're rerendering your components so frequently, but you can try throttling the updates to your redux store. This way you'll show all the latest data to your user without overburdening the CPU.
You can use throttle-debounce package to throttle your socket callback. Subsequent calls to the throttled function will only succeed if a given interval has been passed since the last call.
Hello I am working on a process with React that will allow users to select a row or rows from a table by selecting check-boxes.
I need assistance with how once a row is checked, how can I store this information but at the same time if the row is unchecked I would also want to update the state.
Than when the user selects the submit button it will send the array object to the server side.
I have an empty array in my state and in the method that handles selecting a checkbox I am attempting to push the data to the array and than send the array with a form.
It appears as if the array is not being updated or I am missing something?
class TestStatus extends Component {
constructor (props) {
super(props)
this.state = {
selected: []
}
handleCheckChildeElement = (event) => {
var data = this.global.data;
data.forEach(data => {
if(data.testid === event.target.value) {
data.isChecked = event.target.checked
if(event.target.checked === true) {
this.setState({ selected: [ ...this.state.selected, data]
});
}
console.log(this.state.selected);
}
});
this.setGlobal({ data });
}
handleSubmit(event) {
event.preventDefault();
axios.post('http://localhost:5000/api/advanced_cleanup',
this.state.selected)
.then((res) => {
console.log("Sending tests");
}).catch(event => console.log(event));
}
render() {
return(
<div>
<table>
<AdvancedRows checked={this.handleCheckChildeElement}
handleCheckChildeElement={this.handleCheckChildeElement}/>
</table>
<form className="ui form" onSubmit={this.handleSubmit}>
<button
className="ui basic blue button" type="submit"
style={{ marginBottom: '5em' }}>
Submit
</button>
</form>
</div>
);
}
}
I expect to be able to select a checkbox or multiple and update the state array based on what is checked and than send that data to the server side.
After some additional research online I found the correct way with react to update the state array and than update it upon unchecking a check box.
If the targeted row is checked it will pass that rows object into the state array otherwise if the check box of the row is unchecked it will iterate over the state array and filter out the item that was unchecked.
This is the guide I used to assist me. https://scriptverse.academy/tutorials/reactjs-update-array-state.html
if(event.target.checked === true) {
this.setState({ selected: [...this.state.selected, data ] });
} else {
let remove = this.state.selected.map(function(item) {
return item.testid}).indexOf(event.target.value);
this.setState({ selected: this.state.selected.filter((_, i) => i !== remove) }); }
Expanding on my comment above.
handleCheckChildeElement = (event) => {
var data = this.global.data;
// create an empty array so that each click will clean/update your state
var checkedData = [];
data.forEach(data => {
if(data.testid === event.target.value) {
data.isChecked = event.target.checked
if(event.target.checked === true) {
// instead of setting your state here, push to your array
checkedData.push(data);
}
console.log(checkedData);
}
});
// setState with updated checked values
this.setState({selected: checkedData});
this.setGlobal({ data });
}
I have to make a select menu in react but there is an extra couple functions it needs to have that I haven’t been able to find on the first 50 links of google. (I’m not googling the right thing obviously cause idk what it’s called).
Details:
A select menu that, once an item is selected, carries the item far below the select menu so that the item can be manipulated further. For example, I want to select multiple ingredients and then have them displayed on the same page, in order of selection, and then be able to enter an amount in a text field that is next to the ingredient that has been selected.
Process:
Select paprika (remove paprika from select menu because there is no need to select it again) > see paprika appear far below select menu > enter amount of paprika in text field tied to back end > repeat for other ingredients.
Any help would be greatly appreciated. Even if you just tell me what to google.
Thank you all,
Matt
I tried to write this up in JSFiddle but it was tripping out on me.... Here should be an Almost working example with the same approach that Joss mentioned. I think you'll be able to get the idea from it
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
selected: [],
};
}
select(e) {
const { value } = e.currentTarget;
let { selected } = this.state;
if(selected.contains(value)) {
selected = selected.filter((val) => val !== value);
} else {
selected.push(value);
}
this.setState({
selected,
});
}
render() {
const ret = []; //Just using this to map over to create options
for(i = 0; i < 5; i++) {
ret.push(i);
}
return (
<div className="container">
{ ret.map((i)=>(
<div
onclick={this.select}
value={i}
className={this.state.selected.contains(i) ? 'selected' : null}>
{i}
</div>
)}
</div>
);
}
}
ReactDOM.render(
<Demo />,
document.getElementById('container')
);
I would have an array stored in state that would contain all selected ingredients, which would be updated each time a new ingredient is selected (using onChange). I would then simply use this array to influence what is displayed on the rest of the page.
I a WinJS page with the following HTML snippet:
<div class="productivity-view">
<div class="categorylist" aria-label="Category List">
</div>
<div class="itemlist" aria-label="Work Item List">
</div>
</div>
I am able to programmatically initialize two lists:
var categories = new WinJS.Binding.List(list),
categoryListEl = document.querySelector(".categorylist"),
catList = new WinJS.UI.ListView(categoryListEl, {
itemDataSource: categories.dataSource,
itemTemplate: document.querySelector('.categoryitemtemplate'),
onselectionchanging: function(event) {
var items = event.detail.newSelection.getItems();
items.done(function(selections) {
var selection = selections[0],
item = selection.data,
boxes = categoryListEl.querySelectorAll('.win-itembox');
boxes[catList.currentItem.index].classList.remove('active');
boxes[selection.index].classList.add('active');
workItemHeader.textContent = item.title;
workList.itemDataSource = new WinJS.Binding.List(item.workitems).dataSource;
});
}
});
var workItemListEl = document.querySelector(".itemlist"),
workList = new WinJS.UI.ListView(workItemListEl, {
itemTemplate: document.querySelector('.workitemtemplate'),
onselectionchanging: function() {}
});
The code above listens for the onselectionchanging event on the first list, in which case the event data carries some information used to fill out the second list.
How can I programmatically trigger the onselectionchanging on the first item in the first list?
We figured it out. Solution code below. We wanted to trigger selection of the very first item in the first list, which would then put some information into the second list 'onselectchanging'. This involved listening to the 'onloadingstatechanged' event for the 'complete' state, and then adding the first item in the list to the first list's selection (the missing piece of API knowledge).
var catList = new WinJS.UI.ListView(categoryListEl, {
...
onselectionchanging: function (event) {
...
},
onloadingstatechanged: function () {
if (this.winControl.loadingState === "complete") {
// try to select the first item in the list
catList.selection.add({ key: 0, index: 0, hasFocus: true, showFocus: false });
}
}
});
var workItemListEl = document.querySelector("#itemListControl"),
workList = new WinJS.UI.ListView(workItemListEl, {
...,
onselectionchanging: function () {
....
}
});