ClassName undefined for some child in iconCreateFunction - javascript

The bounty expires in 7 days. Answers to this question are eligible for a +50 reputation bounty.
Nicolas wants to draw more attention to this question.
I'm working in a Vue2 web application using Leaflet and marker-cluster
I have some issue with the iconCreateFunction option
Here is a part of my tempate :
<v-marker-cluster :options="{ iconCreateFunction: iconCreateClsPrg}">
<l-marker ....>
<l-icon :class-name="programme.display ? 'custom-marker notDisplay' : 'custom-marker display'">
And here is a part of the iconCreateClsPrg method :
iconCreateClsPrg (marker_cluster) {
const childs = marker_cluster.getAllChildMarkers();
childs.forEach(child => {
const cssCluster = child.options.icon.options.className;
if (cssCluster && cssCluster.includes(this.css_marker_selected_simple)) {
nbSelected++;
}
}
...
}
My problem is that sometimes my cssCluster const is undefined for no reason. It's not a regular behavior and it happens only at some zoom levels (which are not always the same).
If someone has an idea, it would be a big help !
I tryied to refresh the map, to wait until undefined (but had some issu with async method), restart the method from scratch, use for instead of forEach, ... but nothing worked

Related

Using image dimensions from a URL without loading it onto page - Javascript

I'm currently learning JavaScript in a bootcamp and I'm having a hard time figuring out how to solve a problem. I have googled it extensively, but I feel like I'm missing a core piece of functionality in what I'm trying to do.
I'm getting an array of returned images from an API based on a date specified by a date selector. I want to measure the dimensions of the natural height and width of each item in the array and filter them into another array which I will use to display a gallery. Here is a link to what the API returns:
API returned object array index[0] example
Here is the relevant piece of code, including the API call.
spaceApp.getRoverPhotos = (date) => {
$.ajax({
url: spaceApp.roverUrl,
method: 'GET',
data: {
api_key: spaceApp.key,
earth_date: date,
camera: spaceApp.cameras,
page: 1,
}
}).then((res) => {
//functioning code but doesn't wait for stuff to load.
let displayArray = res.photos.filter( (each) => {
let imageDim = new Image();
imageDim.src = each.img_src;
if(imageDim.naturalWidth >= 1000 && imageDim.naturalHeight >= 1000) {
return true;
}
else {
return false;
}
});
console.log(displayArray);
})
}
The results of this are not consistent, and I think it's the way that the images are being loaded. The filter method is used after a successful promise, so I know that the array consistently returns the information I need, but I don't always get the natural height and width because of the way something is loading. I used a forEach to console log the natural height and width when I submit the date twice in a row. The first returns me no values, the second has them all loaded:
First submit, 25 results of 0 0, then all show upon re-submitting the form
My best guess is this has something to do with caching the images. I've tried to use image.onload in creative ways, but I'm not sure that makes sense, given that I haven't used them on the page anywhere(similarly, I tried imageDim.addEventHandler('load', ()=>{})). I have tried using map to create a new array of images using the new Image() approach above, and then filtering the new array, but I ran into the same issue. I have considered using a promise, but I can't figure out how to "load" images without displaying them on the page, and using that as a promise inside a filter.
I have seen, and tried without success, a few variations of this:
var img = new Image();
img.onload = function() { alert("Height: " + this.height); }
img.src = "http://path/to/image.jpg";
I'm sorry if I'm missing a step here, but I've been working on this for several hours without success. I've asked my only senior developer friend for help, but he wasn't able to provide me much guidance since he happened to not be at home at the time (he suggested I "load" the images into a new array, then filter, but I have the same problem of how to make an image load - I did attempt his suggestion).
If anyone could spare the time to help me I would really appreciate it! I feel I'm at a roadblock because I don't quite know the nature of the true problem I'm experiencing, if someone can tell me what I'm missing I can continue googling it! Thank you in advance!

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.

React: UI not painted correctly with dhtmlx-gantt library when applied with filters

I am using React with dhtmlx-gantt library to create gantt chart. I met with issue when using the filter function together with useEffect/useLayoutEffect lifecycle.
The gist of it is that the browser is not painting/rendering the correct UI on the screen on certain condition.
The start state load screen looks like this:
6 Task
After filter, this should be how it looks like:
Should be left with 5 task after filtering away duration > 4
But this is how it is:
Left with 5 task but an empty row is shown rather than "refreshing" (not sure if this is the right term to use)
I have created a github repo with different scenario describing the problem, and how to reproduce those issue. More information on how to run the sample can be found in the README.md. Please let me know if more information needs to be provided.
Sample 1: Using conditional rendering will cause issue on painting UI changes
Sample 2: Turning smart_rendering config on and off cause issue on painting UI changes
Sample 3: Calling the function within the parent component and in child component with exact same code cause issue on painting UI
My desired outcome is to able to render the UI correctly, whether or not this code to filter the data is ran on parent or child component.
I should also mention that a workaround was to use if (document.querySelector(".gantt_grid")) gantt.render(); rather than gantt.refreshData() in onBeforeTaskDisplay event which will then correctly paint the UI changes. But I still like to understand why does this happens. Is there anything I did wrongly in term of using the React lifecycle and so on.
Thank you.
Your code looks fine and should work correctly.
The issue is on dhtmlxGantt end, it has been confirmed and is now fixed in the dev branch.
The bug itself was caused by the new smart rendering mechanism introduced in v6.2.0.
It caches previously calculated positions of tasks in order to minimize calculations. In certain circumstances when a gantt instance has been initialized multiple times, it didn't invalidate that cache when it was necessary. Because of that, tasks were displayed at the same positions as they had before filtering was applied (thus the blank row where the first task has been).
In short, the issue will be fixed in the next bugfix update - v6.2.6.
If everything goes as planned, it will be released tomorrow (2019-09-19)
Try gantt.render() after gantt.refreshData() in your code:
useEffect(() => {
const onBeforeTaskDisplay = gantt.attachEvent("onBeforeTaskDisplay", function (id, task) {
console.log("filters", task.text, filter)
if (filter && task.duration > 4) {
return false;
}
return true;
});
gantt.refreshData();
gantt.render();
// This should have been here
return () => {
gantt.detachEvent(onBeforeTaskDisplay);
}
}, [filter])

Sencha touch 2 model association saving incorrect data to store

Please refer to the following fiddle: http://www.senchafiddle.com/#xXQlp
Be sure to have your console open to see the output that shows the incorrect data.
Here you can see I'm creating 2 Student models, each of which have a list of 0+ Award models. Dave has been given 2 rather nice awards - unsurprisingly :) - whereas Chaz has added 2 not-so-great awards. The problem is that the logging shows that infact Chaz ends up with 4 awards (the 2 good ones, as well as the 2 bad ones).
This fiddle is a severe boiling down of a much larger app, but I have isolated this as the origin of a huge problem I've been having - I've even found a 'fix' for it. If you uncomment lines 55 and 56 from the fiddle and run it again (be sure to clear your localstorage!), you will see that Chaz only has to 2 awards that he should.
For reasons that I hope are obvious, this is not a fix I'm happy with. There has to be something else I'm doing wrong with the association to cause Chaz to get all 4 awards.
... surely?
Cheers!
UPDATE: Answer below accepted, removing autoLoad:true fixes the problem. I want autoLoad however, so I implemented the following in the init of the Student model:
for (var i=0, l=this.associations.all.length; i<l; i++) {
var assoc = this.associations.all[i];
if (assoc._type == "hasmany") {
var assocName = assoc._name;
var getterName = 'get' + assocName.charAt(0).toUpperCase() + assocName.slice(1);
this[getterName] = function(assocName) {
var self = this;
return function() {
var store = self[assocName]();
if (!store.isLoaded()) {
store.load();
}
return store;
}
}.call(this, assocName)
}
}
This adds a getter for each hasMany association that the student has, and ensures that the store for that association is loaded before returning it. ie I can now access student1's awards with student1.getAwards() rather than student1.awards(), and know that the awards will have been loaded, this will automatically work for any other hasMany associations I add to the model.
I hope this is helpful to some readers.
Not autoloading the awards will resolve this, remove the autoload: true on the students >> awards hasMany association. I don't fully understand why autoloading the awards breaks things though, but this forum thread suggests it's a bug: http://www.sencha.com/forum/showthread.php?195371-autloaded-associations-don-t-properly-filter-data-from-a-JSON-proxy
Your example working: http://www.senchafiddle.com/#xXQlp#S3Af0

Sencha Touch Ext.navigation.View pop to root

I have an Ext.navigation.View in which I have pushed a few views. Certain user interactions require that I go directly back to the top level of the navigation view -- the equivalent of popToRootViewControllerAnimated: on a UINavigationController in iOS.
I have tried various things like:
while(navigationView.getItems().getCount() > 1)
navigationView.pop();
and
while(navigationView.canPop())
navigationView.pop();
Neither work. The first example seems to put me into an infinite loop which isn't too surprising. The second example only seems to pop one view off.
So the question: What is the proper way to pop to the root view in an Ext.navigation.View in Sencha Touch (version 2 developer preview)?
There has been a number of interim methods for achieving this.
The one I was using was to pop a number higher than the number of levels you would ever have e.g.
navigationView.pop(10);
and that worked fine, but I was never happy with that, but I see they have now introduced a reset method. Which you can call thus...
navigationView.reset();
Internally within the Sencha source code (see below) you can see that it does a similar job to what #Mithralas said, but just easier to write.
// From the Sencha source code
this.pop(this.getInnerItems().length);
popToRoot: function() {
this.pop(this.getItems().length - 1);
}
Ensure to use the NavigationView.reset() method. To make it clear, if your main navigation view is Main, you'd do something like this in the controller:
this.getMain().reset();
The solution turned out to be extending the navigation view with the following:
popToRoot: function(destroy)
{
var navBar = this.getNavigationBar(),
stackLn = this.stack.length,
stackRm;
//just return if we're at root
if(stackLn <= 1) return;
//just return if we're already animating
if(navBar && navBar.animating) return;
//splice the stack to get rid of items between top and root
stackRm = this.stack.splice(1, stackLn-2);
//remove views that were removed from the stack if required
if(destroy) {
stackRm.forEach(function(val, idx, arr) {
this.remove(val, true);
});
}
//clear out back button stack
navBar.backButtonStack = [];
//now we can do a normal pop
this.pop();
}

Categories