Infinite scroll in Angular 5, populated by a httpClient request - json

I would like to implement an infinite scroll populated by a very big json, within Angular 5. The idea is to show only the 5 first entries and then, when a user scroll, it shows the 5 more.
Now, I had a look on this : https://github.com/orizens/ngx-infinite-scroll but the array used for the view only take strings.
I had a look at an example : Plunker Example of ngx-infinite-scroll and what cause the problem is this :
addItems(startIndex, endIndex, _method) {
for (let i = 0; i < this.sum; ++i) {
this.array[_method]([i, ' ', this.generateWord()].join(''));
}
}
Where this.generateWord() only generate random strings and _method is push or unshift.
How could I push or concat parts of an object into this so I can still make it work with my *ngFor inside my html template ?
Any idea of a plugin that accept http request object or how to make ngx-infinite-scroll work ?
Thanks

Ok, I didn't follow "best practices" for the code layout and don't show how to actually get data from a server to populate it ... but I did answer the basic question of how to use an object instead of a string to display.
The result is here: https://stackblitz.com/edit/angular-a5ew8f
I just replaced the hard-coded string with entries from a hard-coded array:
addItems(startIndex, endIndex, _method) {
let movieIndex=0
for (let i = 0; i < this.sum; ++i) {
movieIndex++;
if (movieIndex >= this.movies.length) movieIndex=0;
this.array[_method](this.movies[movieIndex]);
}
}
In a real application, you would want to go to the server to get 'n' (this.sum) more items each time the addItems method is called.

Related

Increasing Value of State Variable in ForEach loop for Progress Bar in React

I'm trying to figure out a way to build a progress bar with React. I have a forEach loop that iterates through an array of about 7,000 indexes. Each time I validate a row, I want to update a state variable with percentage completion (and render this on the page live). I've tried iterating through these indexes, and updating my state variable (hoping to update the page) in the loop but I'm realizing that will not work. I obviously can't do this with a normal variable as it will reset when the component re-renders. Can anyone give me some insight on this topic?
Thanks.
Here is a code snippet from what I'm looking at:
parsedAssets.forEach(asset => {
newAssetValidated = validateBulkUpload(asset, parsedAssets, assetList, accountLogged, jobSites);
!newAssetValidated.reject_err ? validatedAssetList.accepted.push(newAssetValidated) : validatedAssetList.rejected.push(newAssetValidated);
setStateAssets({ ...stateAssets, validatedAssetList });
});
}
So essentially, as each asset is either accepted or rejected we add it to "stateAssets", and I'm hoping to build the progress bar from the length of the combined arrays that are getting set in stateAssets. However, when the forEach loop is completed, only the last validated asset is getting set due to it not updating until the forEach loop is completed.
Personally I can't imagine such a heavy validation, that you need progress-bar, but anyway.
First solution is to separate validation itself from state update for progress-bar into separate "threads". But since JS is single threaded, you may use some tricks with setTimeout or setInterval functionality. It may be very tricky, and in general not recommended practice with React.
Another way is - to set the work into queue & process 1 item at a time.
As an example I would do it something like this:
function ComponentWithProgress({parsedAssets, setParsedAssets}) {
const [validatedAssetList, setValidatedAssetList] = useState([])
const [progress, setProgress] = useState(0)
const [toDo, setToDo] = useState([])
if(parsedAssets && parsedAssets.length>0) {
setToDo(parsedAssets)
// clear parsedAssets in parent component to: [], false, null ...
// so you put it into toDo only once
setParsedAssets([])
}
if(toDo.length > 0) {
const asset = toDo[0]
const newToDo = toDo.slice(1) // All but 0th element
const newAssetValidated = validateBulkUpload(asset);
setValidatedAssetList([ ...validatedAssetList, newAssetValidated ]);
setToDo(newToDo)
setProgress( newToDo.length / ( validatedAssetList.length + newToDo.length ) * 100 )
}
// ... Render here
// If you need only accepted
const accepted = validatedAssetList.filter(v => !v.reject_err)
}
This example maybe not work for you as is, because you didn't showed us the context, but the main idea is here.

Using Query String Parameters instead of a "Range:" HTTP Header in Dojo's JsonRest

I'm trying to set up pagination in Dojo. I basically have a table with thousands of records, and I want to display them page-by-page to the user instead of all at once. I'm using dgrid with a JsonRest store. Per JsonRest's documentation, the store uses HTTP's "Range:" header to perform paging. When a request is made for a range of items, the store will include a "Range:" header with an items range unit specifying the range. (http://dojotoolkit.org/reference-guide/1.10/dojo/store/JsonRest.html) Unfortunately this is a big problem because some of our users are behind proxies that filter out HTTP's range header. The only workaround I see is to use query string parameters instead of the "Range:" HTTP header. So I'd have a URL that would look something like:
http://myhost.com/myapp/things?start=10&end=19
instead of having the Range Header be "Range: items=0-24"
How would I go about solving this issue? If you have a suggestion for an alternative workaround, that would be greatly appreciated as well.
I found an easy solution to this. Simply overwrite Dojo's JsonRest class and use it instead of JsonRest when you create your dgrid.
define(["dojo/_base/declare", "dojo/store/JsonRest"], function(declare, JsonRest){
var base = JsonRest;
return declare("myapp.JsonRest2", base, {
query: function(query, options){
if(options.start >= 0 || options.count >= 0){
query.start = options.start >= 0 ? options.start : 0;
query.count = options.count >= 0 ? options.count : 10;
}
return this.inherited(arguments);
}
});
});

How do i populate an Array in one class based on a textfield in another class?(Actionscript 3.0)

i have a class (TheList.as). in which i have an array "Data" and it has a couple of values. Then i have a loop through which i am creating a scrollable list which uses the values from "Data" array. [I am trying make a unit converter]
Then i have another class "Units.as". In that class i have created three instances of "TheList". A main list ("myList"), and to sublists "ListFrom" and "ListTo". They are using values from "Data" array. Now i have text field whose value changes to whatever item is clicked. When i click "Angle" in the main list, i want the sublists to get populated with ("Degree", "Radian" etc)..
Here is what i tried
if(myList._TextLabel.text == "Angle")
{
ListFrom.Data = ["Degree", "Radian"];
}
But nothing happens, i do not get any error either. When i do this in an "ENTER_FRAME" event and trace (ListFrom.Data), i can see that the values change, but they do not get assigned to the list items in the list. I would really appreciate the help. Thanks!
Here are complete Classes for understanding the situation better(the code is pretty messy, as i am a newbie to OOP)
TheList.as: http://pastebin.com/FLy5QV9i
Units.as : http://pastebin.com/z2CcHZzC
where you call ListFrom.Data = ["Degree","Radian"], make sure when the data changed, the renders in the ListFrom have been set new data. for example, you may use MyRender in ListFrom for show, you should debug in the set data method in MyRender.
you should call the code below after you call ListFrom.Data = ["Degree","Radian"];
for (var i:int = 0; i < Data.legnth;i++) {
var render:MyRender = ListFrom[i] as MyRender;
if (render) {
render.data = Data[i];
} else {
var render:MyRender = new MyRender();
render.data = Data[i];
ListFrom.addChild(render);
}
}
You can use event listeners, singleton classes or reference one class to another, depending on the style you want. All are equally valid and fast / efficient.

google visualization api, identify tableid in response function

Hmmm, maybe someone can help me out here or point me in the right direction , as i have been banging my head against the wall for a number of days now and dont seem to be gettin anywhere useful.
(and admittedly i'm pretty new with regards to json,objects, google visulization etc)
essentially, i am running 3 different queries on the same page against 3 different fusion tables, which in return are supposed to return an array of 3 different xets of markers.
all is fine, when i run the queries individually and make an array of the markers .
however, running the 3 queries on the same page, i can't seem to find a way to identify the query in the response function.
any hints much appreciated. and i'll be happy to provide more info if needed (tried to get rid of some unneccessary stuff)
this is what i have. thanks
a) calling the function "setFusionData()" with all relevant vars. something like setFusionData("'LatLng','name'", 2729461);
(this is calles 3 times with different variables)
function setFusionData(selColumns,tableId) {
/****
an actual query example is this:
http://www.google.com/fusiontables/gvizdata?tqx=reqId:1234&tq="select+'LatLng','name'+from+2729461"
****/
var query = new google.visualization.Query(
'http://www.google.com/fusiontables/gvizdata?tqx=reqId:1234&tq='+ encodeURIComponent("SELECT "+selColumns+" FROM "+tableId+"")
);
query.send(getFusionData); //do something with the response
}
function getFusionData(response) {
/**
here, is the problem as i need to get the table id or reqId or anything that is uniquely passed on from "setFusionData" above
also something like
alert(JSON.stringify(response)) does not return any reqId or table id either
***/
/*return rows/columns and add values to an array of markers***/
var numRows = response.getDataTable().getNumberOfRows();
var numCols = response.getDataTable().getNumberOfColumns();
for (i = 0; i < numRows; i++) {
/* add markers to array etc this works fine***/
}
}
i also tried something like this:
function setFusionData(selColumns,tableId) {
......
query.send(getFusionData({reqId:tableId}));
}
function getFusionData(response) {
alert(response['reqId']);//returns tableId. but how do i get the tableData ?
}
with wich i can get the reqId, but not the table*Data*. So I am only able to get either id or data :(
----edit----------------
after messing around a bit more (see below) it appears that the key/value pairs that get returned when typing the query into the browser directly are different than what gets returned by the call from the script...i.e the following
http ://www.google.com/fusiontables/gvizdata?tqx=reqId:1234&tq="select+'LatLng','name'+from+2729461"
typed directly into the browser bar will return
version:'0.5',reqId:'1234',status:'ok',table etc
however, calling the same from within the script returns something like
{
"rj":"0.5","ef":"ok","pb":[],"qb":[],"h":"{"cols":
[{"id":"col2","label":"LatLng","type":"string"},{"id":"col1","label":"name","type":"string"}],
"rows":
[{"c":[{"v":"47.20572,12.70414"},
{"v":"Hohe Tauern"}]},{"c":[{"v":"47.5530395,12.925611"},{"v":"Berchtesgaden"}]},{"c":[{"v":"47.5585405,14.61887"},{"v":"Gesu00e4use"}]}],
"p":{"totalrows":3}
}"
}
, so no 'reqId' but only some cryptic keys (without one that looks like the reqId either)...... anyone any idea why that would/could be ?
Sometimes you can figure it out by just looking at the JSON response, your sample request returns:
google.visualization.Query.setResponse({
version:'0.5',
reqId:'1234',
status:'ok',
table: {
...
}
})
You already got response.reqId to identify which request is this the response for, now you can use response.table to create a new DataTable instance:
var dt = new google.visualization.DataTable(response.table);
Or, since you have multiple tables, put then in an array indexed with the reqId
tables[response.reqId] = new google.visualization.DataTable(response.table);
You'd do var tables = new Array() before calling setFusionData() for the first time.

How to find specific value in a large object in node.js?

Actually I've parsed a website using htmlparser and I would like to find a specific value inside the parsed object, for example, a string "$199", and keep tracking that element(by periodic parsing) to see the value is still "$199" or has changed.
And after some painful stupid searching using my eyes, I found the that string is located at somewhere like this:
price = handler.dom[3].children[3].children[3].children[5].children[1].
children[3].children[3].children[5].children[0].children[0].raw;
So I'd like to know whether there are methods which are less painful? Thanks!
A tree based recursive search would probably be easiest to get the node you're interested in.
I've not used htmlparser and the documentation seems a little thin, so this is just an example to get you started and is not tested:
function getElement(el,val) {
if (el.children && el.children.length > 0) {
for (var i = 0, l = el.children.length; i<l; i++) {
var r = getElement(el.children[i],val);
if (r) return r;
}
} else {
if (el.raw == val) {
return el;
}
}
return null;
}
Call getElement(handler.dom[3],'$199') and it'll go through all the children recursively until it finds an element without an children and then compares it's raw value with '$199'. Note this is a straight comparison, you might want to swap this for a regexp or similar?