Svelte make {:then} value of {#await} statement reactive - request

I have to make an api call and then display the data (an array). I want to sort the array, but the displayed data is not updated. I suppose this is because my data is not a reactive variable? How can I make my each loop rerun when data changes?
My code (simplified):
{#await promise} // api call
<p>Loading</p>
{:then data}
<button on:click={() => data.sort()}>sort data</button> // does not work
{#each data as student}
<p>{student.firstname}</p>
{/each}
{/await}

data is a reactive variable. The presence of a promise is unrelated to the issue: this occurs even if data is a normal variable. The issue is that Svelte doesn't properly pick up that a change occurred to data when you click the button. You can force Svelte to pick up the changes by explictly assigning to data.
The other issue is that you can't sort objects without providing a custom sort function to sort based on a key of the object. .sort((a, b) => a.firstname.localeCompare(b.firstname)) sorts based on the firstname property of the objects.
Putting that together gives us:
<button on:click={() => data = data.sort((a, b) => a.firstname.localeCompare(b.firstname))}>sort data</button>

Related

How to map data from an array of objects for an options selector product in react?

I'm simply trying to map data from an API with the intention of creating options to select for a product.
I am able to do it as long as the API data for the specific concept (for example bluetooth, color, weight) has a simple array format as:
"bluetooth":["4.0","A2DP","LE"]
Then using the following code renders the options to choose on the selector
<OptionsCss onChange={(e) => setSize(e.target.value)}>
{product.bluetooth?.map((s) => (
<FieldCss key={s}>{s}</FieldCss>
))}
However with a concept named storage I'm unable to get the values on the product options to choose. Here the array structure is as follows :
"storages":[{"code":2000,"name":"16 GB"},{"code":2001,"name":"32 GB"}]
Here I just need the values as for example 16GB and 32GB. So mapping the api following the previous way gives me empty choice options.
Then the question would be, How can I get access to the name values from the example mentioned
previously ? and what should I change from the previous mapping example?
When you map through the array, you get one object at a time then you can access the property you want from the object using storage.name.
obj.storages.map(storage => storage.name)
So in the case of your component you'd have
<OptionsCss onChange={(e) => setSize(e.target.value)}>
{product.storages?.map((s) => (
<FieldCss key={s.name}>{s.name}</FieldCss>
))}
/>

ReactJS Calling method with onClick doesn't work fully

so i'm making a sorting visualization in ReactJS.
I have a method called "bubbleSort" that will follow bubble sort algorithm to sort array.
I have an array generated and visualized on the screen called "array".
Now when i use
<button onClick={bubbleSort(array)}>Click here to sort</button>
It will Sort the array and change the visualized array automatically everytime the page loads. It's not what i want, i want it to sort the array and change the visualization when i click the button.
So i made another method like this
function doSort() {
bubbleSort(array);
console.log(array);
}
and call the button like this <button onClick={doSort}>Click here to sort</button>, it will sort the array, but the visualized array on the screen stay the same (random) and is not display correctly (sorted). I'm stuck and don't know what to do. Thank you very much for your time to help me.
welcome to StackOverflow, I think you should call the function using the pattern below.
<button onClick={() => bubbleSort(array)}>Click here to sort</button>

State object.map() returning error - what am I overlooking?

I would appreciate a second pair of eyes on this...
The React Component is reading-in data from MariaDB within a useEffect(). The data is being read-in without error and a console.log displays the correct data (see image below). In the return() section of the FunctionalComponent, I have this code:
<div class={style.tblBody}>
{tableData !== undefined &&
tableData.map((row: RDPresData) => {
return `<div>${row.title}</div>`;
})}
</div>
Here is the console error I receive (note the logged data above the red error).
I'm sure that at 3:30am I am missing something obvious...
Looking at your console.log output you can tell that tableData is an object, not an array. It says:
{tableData: {...}}
If it was an array, it would say:
{tableData: [...]}
For some reason, the tableData object happens to have numerical keys, like an array, but since it's not actually an array, .map doesn't exist.
If you do console.log(tableData) get above result. So you should get correctly object tableData and parse it to array to use map. Because map function is working for array.
Your tableData is an object. You should get values before use map.
<div class={style.tblBody}>
{tableData?.tableData !== undefined &&
Object.values(tableData.tableData).map((row: RDPresData) => {
return `<div>${row.title}</div>`;
})}
</div>

How to repeat an array n times using JSX

I am using React/JSX in my app.
i need to reapet data from API n times in first time. if i click on button it reapet more n times. another click-> another n times reapet and over and over.
the api give me 1 results every time. i can define results if it necessary
my code:
const n=2;
arr:[];
handleClick(){
//i need the code to increase n another 2 times
}
//the array here without the code to fill api data. not relevant
this.state.arr.map((d,key)=>
<span>age: {d.age} </span>
<button onClick={this.handleClick} >
Expected result in first results:
age:20
age:24
after click on button:
age:20
age:24
age:48
age:19
Depends on where your API call is, but in order to update the array, you should be using this.setState in your handleClick
handleClick() {
this.setState({
arr: this.state.arr.concat(newContentArray)
})
}
No clue how your obtaining the data, but that's the general principle. Take your existing this.state.arr and concat the array with the new data.
Be sure to use bind or an arrow function on your button event handler.

Maximum call stack size exceeded in angularJS, when I try use | filter:searchText

I try to filter data using |filter in the ng-repeat directive.
ng-repeat="item in transactions |filter:searchText"
transactions is array with data, which looks like this:
{
$$hashKey: "object:666",
amount: -50,
card: "3158",
catId: 0,
dateTime: {month: 2, value: "2015-02-23T14:00:00"}
details: "blabla",
id: 2830,
}
searchText - is text which inputted by user.
It has to filter data when user inputs text, but it doesn't work because it throws exception(Maximum call stack size exceeded). It normally works if definitely to write what kind of fields you want to use to filter data.
ng-repeat="item in transactions |filter:{amount:searchText}"
I had this same problem with a very simple filter, but I was filtering on an array of objects that had a circular reference. I wasn't making any function calls on the filter - it was just the built-in filter on a simple string.
I had two lists of objects with a many-to-many relationship, and once loading them from a $resouce I had set them each up with a property that was an array of all the objects in the other list with which they had a relationship. I had a list of jobs that tracked its own list of tasks, and a list of tasks with its own sublist of jobs.
for (let job of service.jobs)
{
job.tasks = service.tasks.filter(t => t.jobid == job.id);
}
for (let task of service.tasks)
{
task.jobs = service.jobs.filter(j => j.taskid == task.id);
}
(The relationship was a little more complex that this, but this was the heart of it).
I was trying to save cycles by associating them up front just once rather than every digest through the page, but it created a circular loop that only caused a problem once I tried to filter them. I probably could have limited it to filter on the non-"task" fields, but I actually do want to look through them as well. I changed it so that the view just calls the function to pull the related objects inline in the template.
<div ng-repeat="job in service.jobs | filter:jobFilterText"> <-- BOOM
<div ng-repeat="task in service.getTasksForJob(job.id)">
{{ task.name }}
</div>
</div>
The other option I considered was creating a shallow copy of the objects to put in their sub-arrays without the reference back to the original object types, but until I hit a performance problem with the inline binding I prefer its simplicity.

Resources