Ag-Grid rowDataChanged not firing properly - javascript

Here is my onDataChanged() event. It's plugged into my Ag-Grid HTML. It does fire (3 times) but each time it only thinks there's 1 row being displayed. I'm using the serverSide row model and data coming in from the server is a bit slow, so I think that's the problem. I need to have this event fire when the data is changed though, so I can perform some actions when I have a full list of data. At the moment, again, it only ever thinks there's 1 row being displayed when I see that there are 20 in the list.
onDataChanged: function(event) {
var count;
console.log("data changed");
count = this.gridOptions.api.getDisplayedRowCount();
console.log(count);
}
// only ever outputs "1" even though I see 20+ items in the list
Because I'm using the serverSide row model, I'm using a serverDatasource to populate the data. Is there another way to detect when data has been changed? Thank you

Related

How to define where function is slows down?

I have report view where a bunch of controls located, there is an example code:
#Html.DevExpress().DropDownEdit(
settings =>{
settings.Name = "SomeList";
settings.Width = 100;
settings.SetDropDownWindowTemplateContent(c =>{
#Html.DevExpress().ListBox(
...
).BindList(ViewData["SomeList"]).Render();
some code...
).GetHtml()
When it render first time it works fine, but in business logic there is another drop down let's call it dropdown #2. When user select some values in dropdown#2 JS handle this action send request to the server to get actual value for first dropdown, then clear all rendered values from dropdown #1 and insert new items.
And problem in performance lies in how devexpress create new items on client side. From backend there is now 8000 new items can be added to dropdown #1 and it keep growing. And user must wait 5-10 seconds when browser render it. I tried to research what is happening when new item is creating but there are a lot of devexpress function which call another functions.
JS code look's like:
SomeList.BeginUpdate();
l = data.SomeList.length;
while (x < l) {
SomeList.AddItem(data.SomeList[x].Name, data.SomeList[x].Id);
x++;
}
SomeList.EndUpdate();
BeginUpdate and EndUpdate is devexpress functions that prohibbit browser render control while adding new items. Without this function it takes eternity to finish adding new items.
I know start point of problem it is - item creating code SomeList.AddItem(...).
So my question: is there way to do something like console.trace(SomeList.AddItem(...)) and see full trace which will be executed on first code pass?
Also is there way to determine which function call take alot of time to execute?

Ag-grid: duplicate node id 107 detected from getRowNodeId callback , this could cause issues in your grid

I am going to do live data streaming on ag-grid datatable, so I used DeltaRowData for gridOptions and added getRowNodeId method as well which return unique value 'id'.
After all, I got a live update result on my grid table within some period I set, but some rows are duplicated so I can notice total count is a bit increased each time it loads updated data. The question title is warning message from browser console, I got bunch of these messages with different id number. Actually it is supposed not to do this from below docs. This is supposed to detect dups and smartly added new ones if not exist. Ofc, there are several ways to get refreshed data live, but I chose this one, since it says it helps to persist grid info like selected rows, current position of scroll on the grid etc. I am using vanilla js, not going to use any frameworks.
How do I make live data updated periodically without changing any current grid stuff? There is no error on the code, so do not try to speak about any bug. Maybe I am wrong with current implementation, Anyway, I want to know the idea or hear any implementation experience on this.
let gridOptions = {
....
deltaRowDataMode: true,
getRowNodeId = (data) => {
return data.id; // return the property you want set as the id.
}
}
fetch(loadUrl).then((res) => {
return res.json()
}).then((data) => {
gridOptions.api.setRowData(data);
})
...
If you get:
duplicated node warning
it means your getRowNodeId() has 1 value for 2 different rows.
here is part from source:
if (this.allNodesMap[node.id]) {
console.warn("ag-grid: duplicate node id '" + node.id + "' detected from getRowNodeId callback, this could cause issues in your grid.");
}
so try to check your data again.
if u 100% sure there is an error not related with your data - cut oof the private data, create a plinkr/stackblitz examples to reproduce your issue and then it would be simpler to check and help you.

Go to an anchor point in a template with code in Angular 4

I have an Angular 4 application in which I need to add the following functionality:
There is a component with a list of objects. When the user double clicks on one of them, the app retrieves from a DB a list of objects and it should scroll to where the object appears.
I'd like to know how I could move to the desired position in the data once that it has been displayed in the browser. Right now, I have the following code:
let objElement = document.querySelector("#object_"+searchItem._objectID);
if (objElement){
objElement.scrollIntoView();
console.log("****** SCROLLING TO OBJECT");
}
The problem is that, the first time that I load the data from the DB, it seems that 'document.querySelector' returns null, as if the HTML wasn't 100% constructed yet, so it doesn't scroll to the position. If I try to locate the element again, it scrolls perfectly (as it doesn't reload the data from the DB).
Is there a "more Angular" way of doing this? I'm trying to find an example like this in the Angular Router documentation but I can't find anything...
EDIT:
To make things clearer, this is the pseudo-code that I run when the user selects an object:
if(selectedObject IS IN currentLoadedObjects) {
scrollTo(selectedObject); // This function runs the code above
}
else { // The object is in a different list, so retrieve it from the DB
ObjectService.getObjectListFromDB(selectedObject)
.subscribe((returnedList) => {
displayObjectList(returnedList); // Basically, this function parses the returned data, which is displayed in the template using an *ngFor loop
scrollTo(selectedObject);
});
}
As you can see, I try to scroll to the object inside the 'subscribe' method, once that I have the data from the database and after I've parsed it. The object list is pretty big, so it takes 1-2 seconds to be displayed in the browser.
Thanks!

Dynamically loading a database based on user text input

I have an autocomplete widget which needs to return options from a database of objects.
On doing so, once the user selects an item the widget will populate other hidden textfields with values from the particular object they chose. - All of this works and has been used on previous projects
However this particular database is far too big (44k+ objects, filesize is several mb and has taken far too long to load in practice) so we've tried various ways of splitting it up. So far the best has been by first letter of the object label.
As a result I'm trying to create a function which tracks the users input into a textfield and returns the first letter. This is then used to AJAX a file of that name (e.g. a.js).
That said I've never had much luck trying to track user input at this level and normally find that it takes a couple keystrokes for everything to get working when I'm trying to get it done on the first keystroke. Does anyone have any advice on a better way of going about this objective? Or why the process doesn't work straight away?
Here is my current non-working code to track the user input - it's used on page load:
function startupp(){
console.log("starting");
$("#_Q0_Q0_Q0").on("keyup", function(){
console.log("further starting!");
if($("#_Q0_Q0_Q0").val().length == 1){
console.log("more starting");
countryChange(($("#_Q0_Q0_Q0").val()[0]).toUpperCase());
}
else{
console.log("over or under");
}
});
}
And an example of the data (dummy values):
tags=[
{
label:"label",
code:"1",
refnum:"555555",
la:"888",
DCSF:"4444",
type:"Not applicable",
status:"Open",
UR:"1",
gRegion:"North West"
},
....
];
edit: fixes applied:
Changed startupp from .change(function) to .on("keyup", function) - keydown could also be used, this is personal preference for me.
Changed the autocomplete settings to have minLength: 4, - as the data starts loading from the first letter this gives it the few extra split ms to load the data before offering options and also cuts down how much data needs to be shown (helps for a couple of specific instances).
Changed how the source is gathered by changing the autocomplete setting to the following:
source: function(request, response) {
var results = $.ui.autocomplete.filter(tags, request.term);
response(results.slice(0, 20));
},
where tags is the array with the data.
all seems to be working now.
You should bind to keydown event:
function startupp(){
console.log("starting");
$("#_Q0_Q0_Q0").keydown(function(){
console.log("further starting!");
if($(this).length() == 1){
console.log("more starting");
countryChange(($(this).val()[0]).toUpperCase());
}
else{
console.log("over or under");
}
});
}

ExtJs 4.2 ref-selector vs Ext.getcmp() vs Ext.ComponentQuery.query()

I was asked to develop a tab panel with 6 tabs, each having 30 to 40 elements. Each tab is acting as a form in accumulating the details of a person and the last tab is a Summary page which displays all the values entered in the first five tabs. I was asked to provide summary as a tab because, the user can navigate to summary tab at any instance and look at the details entered by him/ or glace the summary. i am following ExtJs MVC pattern. Payload is coming from / going to Spring MVC Application. (JSON)
Using tab change event in controller and if the newtab is summary I am rendering the page with show hide functionality.
Method 1 :In controller I have used Ext.getCmp('id of each element inside the tabs') and show hide the components in summary tab based on the value entered by the user. This killed my app in IE8 popping a message saying that the "script is slow and blah blah..." i had to click on NO for 5 to 6 times for the summary tab to render and display the page.
Method 2 :In controller I used ref and selectos to acccess all the items in tabs. I have used itemId for each and every field in summary tab. like this.getXyz().show(). I thought it would be fast. Yes it was in Google chrome. but my app in IE8 is slow compared to goolge chrome/firefox
Any suggestions regarding this and plan to decrease page render time. The summary page has more than 1000 fields. Please feel free to shed ur thoughts or throw some ideas on this.
thank you!!
I've got a few suggestions you can try. First, to answer your title, I think the fastest simple way to lookup components in javascript is to build a hash map. Something like this:
var map = {};
Ext.each(targetComponents, function(item) {
map[item.itemId] = item;
});
// Fastest way to retrieve a component
var myField = map[componentId];
For the rendering time, be sure that the layout/DOM is not updated each time you call hide or show on a child component. Use suspendLayouts to do that:
summaryTabCt.suspendLayouts();
// intensive hide-and-seek business
// just one layout calculation and subsequent DOM manipulation
summaryTabCt.resumeLayouts(true);
Finally, if despite your best efforts you can't cut on the processing time, do damage control. That is, avoid freezing the UI the whole time, and having the browser telling the user your app is dead.
You can use setTimeout to limit the time your script will be holding the execution thread at once. The interval will let the browser some time to process UI events, and prevent it from thinking your script is lost into an infinite loop.
Here's an example:
var itemsToProcess = [...],
// The smaller the chunks, the more the UI will be responsive,
// but the whole processing will take longer...
chunkSize = 50,
i = 0,
slice;
function next() {
slice = itemsToProcess.slice(i, i+chunkSize);
i += chunkSize;
if (slice.length) {
Ext.each(slice, function(item) {
// costly business with item
});
// defer processing to give time
setTimeout(next, 50);
} else {
// post-processing
}
}
// pre-processing (eg. disabling the form submit button)
next(); // start the loop
up().down().action....did the magic. I have replaced each and every usage of Ext.getCmp('id'). Booooha... it's fast and NO issues.
this.up('tabpanel').down('tabName #itemIdOfField').actions.
actions= hide(), show(), setValues().
Try to check deferredRender is true. This should only render the active tab.
You also can try a different hideMode. Especially hideMode:'offsets ' sounds promising
Quote from the sencha API:
hideMode: 'offsets' is often the solution to layout issues in IE specifically when hiding/showing things
As I wrote in the comment, go through this performance guide: http://docs.sencha.com/extjs/4.2.2/#!/guide/performance
In your case, this will be very interesting for you:
{
Ext.suspendLayouts();
// batch of updates
// show() / hide() elements
Ext.resumeLayouts(true);
}

Categories