Javascript called by blazor code happens when DOM not yet ready? - javascript

I've a javascript function that has to create graph:
<script>
window.setGraph = (lab, ser) => {
console.log(document.getElementById("weather-chart"));
console.log(lab);
console.log(ser);
var chart = new Chartist.Line('#weather-chart', {
labels: lab,
series: ser
});
console.log("done");
return true;
}
</script>
This function is called by one of my blazor component:
protected override async Task OnInitAsync()
{
some-data-a = await RetrieveSomeData();
some-data-b = await RetrieveSomeOtherData();
JSRuntime.Current.InvokeAsync<bool>("setGraph", some-data-a, some-data-b);
}
Everything is executed, my console.log are called. But it appears that at this moment my element #weather-chart cannot be found, because I get this:
chartist.min.js:8 Uncaught TypeError: Cannot read property 'querySelectorAll' of null
at Object.c.createSvg (chartist.min.js:8)
at f.d [as createChart] (chartist.min.js:8)
at f.h (chartist.min.js:8)
AND
my console.log(document....) is returning null.
If I go to this page, I've the error, and if just after getting this error I do something like window.setGraph([1,2,3], [[1,2,3]]) in my chrome developer tools, everything is initialized correctly.
So what did I do wrong? Why chartist doesn't seems to be able to find the element?

It appears that blazor's databinding was taking some time to display the html. So basically after I set the _items, it was changing the template, but not fast enough for the line after this(not sure why, since there was an await).

Related

Change of styling based on TypeScript function return

I am trying to change the visibility style of a div element in a svelte component based on a typescript function.
The sample code is like the ones below:
<script>
const abc = () => {
if (RecipientNumberOffScreen == 0) {
return document.querySelector<HTMLElement>('.recipients__OffScreen').style.visibility = 'hidden'
} else {
return RecipientNumberOffScreen // a calculated variable
}
}
</script>
<div class="recipients">
<div class="recipients__OffScreen">{abc()}</div>
</div>
And I am getting the following error in the console
Uncaught TypeError: Cannot read properties of null (reading 'style')
What I could understand by debugging that the document.querySelector<HTMLElement>('.recipients__OffScreen') is getting null value because first the JS gets loaded in the DOM, and then the html codes are being loaded. I was wondering if there is any way to make the function execution wait before the html gets loaded in svelte? Or what is the best way to achieving it?
I am very new to svelte, thanks in advance.

Cannot read property of undefined of an apparently NOT undefined - SOLVED

I am using a control of Telerik (AutoCompleteBox) which contains an embedded dropdown control that can be accessed through the property _dropDown. I am using the dropDownItemDataBound event to trigger the following code:
var autoComplete = $find("<%= RadAutoCompleteBox1.ClientID %>");
console.log(autoComplete._dropDown._items);
When I click over the [] in the console I get this (that is expected):
[]
0: b.RadAutoCompleteBox.DropDownItem
_attributes: c.AutoCompleteBoxAttributeCollection {_data: {…}, _keys: Array(0)}
_element: null
_template: null
_text: "Chevrolet TRAVERSE "
_value: "GM1"
Thus I supposed that I could do this:
var autoComplete = $find("<%= RadAutoCompleteBox1.ClientID %>");
console.log(autoComplete._dropDown._items[0]._text); // Chevrolet TRAVERSE
console.log(autoComplete._dropDown._items[0]._value); // GM1
Instead I get:
Uncaught TypeError: Cannot read property '_text' of undefined
It doesn't make sense to me because since autoComplete._dropDown._items is obviously an array (and it's NOT undefined!) I should be able to access it by indexing it and get the property contents. Not?
EDIT:
Following the suggestion of #ChrisG that mentioned that perhaps the arry was STILL empty when I tried to log the data to the console, I changed my code into the event to this (to give it a little time and see what happens):
waitAndDisplay();
function waitAndDisplay(timeout = 50) {
setTimeout(function () {
var autoComplete = $find("<%= RadAutoCompleteBox1.ClientID %>");
console.log(autoComplete._dropDown._items[0]._text);
}, timeout);
}
Indeed it worked however it doesn't seem to be a safe approach. Any idea on how to ENSURE that the data is fully loaded before to try to read it?
SOLUTION:
I was after the suggestion of #ChrisG on use a callback to data loaded and figured that I goofed in the documentation of the control because in fact there IS an event that triggers after the dropdown is fully loaded, so I will post the solution here. This way the callback function to be used is OnClientRequested and not the dropDownItemDataBound as I did initially:
function OnClientRequested(sender, eventArgs) {
var myarray = eventArgs.get_data();
console.log(myarray[0].Text);
console.log(myarray[0].Value);
}
It will return the proper data.

Magento 2 error in swatchRenderer.js

I have overridden magento SwatchRenderer.js file in app\code\Mydirectory\CustomSwatches\view\frontend\web\js\SwatchRenderer.js.
My problem is I get an error in my product page load:
Uncaught TypeError: Cannot read property 'updateData' of undefined
I found out that data('gallery') on SwatchRenderer.js's following function is undefined.
updateBaseImage: function (images, context, isProductViewExist) {
var justAnImage = images[0];
if (isProductViewExist) {
context
.find('[data-gallery-role=gallery-placeholder]')
.data('gallery')
.updateData(images);
} else if (justAnImage && justAnImage.img) {
context.find('.product-image-photo').attr('src', justAnImage.img);
}
}
I checked a Magento 2 demo site. On that site the above data attribute is set as a JavaScript object. The target element is a div with the above attribute. But in my site it is undefined and obviously I think that data attribute is not set on my site. Can anyone help me to find the setter function/view/file for above element? Any help would be appreciated. Thanks.
What theme was used in your Magento instance? Did you rename the container class names?
One interesting piece of code is found on line 202 of the SwatchRenderer.js file. Under the _create function you will find the initialization of the gallery variable as seen here
You will notice that it finds the element with the data-gallery under the .column.main element. Thus, as missing column main element would return an empty response.
I found a pretty efficient way to fix this:
Copy the /vendor/magento/module-swatches/view/frontend/web/js/swatch-renderer.js-file to app/design/YourName/YourTheme/Magento_Swatches/web/js/swatch-renderer.js and replace the code inside updateBaseImage() (line ~1152) with the following:
updateBaseImage: function (images, context, isInProductView, eventName) {
var gallery = context.find(this.options.mediaGallerySelector).data('gallery');
if (eventName === undefined && gallery !== undefined) {
this.processUpdateBaseImage(images, context, isInProductView, gallery);
} else {
context.find(this.options.mediaGallerySelector).on('gallery:loaded', function (loadedGallery) {
loadedGallery = context.find(this.options.mediaGallerySelector).data('gallery');
this.processUpdateBaseImage(images, context, isInProductView, loadedGallery);
}.bind(this));
}
},
The trick is: this method doesn't wait for the gallery to be fully loaded, while this event (gallery:loaded) is readily available. By adding this to the method, it works fine.
I just hope that the Magento Dev's pick up on this and implement this in the core-code.

js Model Animation Using three.js r68

As stated in the title, I cannot get animation to work. I'm pretty sure I'm missing something in my code because it works here, but not where I'm testing.
I create the animation object in playerCharacter.js with
this.init = function(){
for (var k in this.mesh.material.materials) {this.mesh.material.materials[k].skinning = true;}
this.animation = new THREE.Animation(this.mesh, this.mesh.geometry.animations[0].name);
this.animation.play();
}
In the update function I use:
this.animation.update(0.017);
And when I look at the console log I get:
Uncaught TypeError: Cannot read property 'length' of undefined
So it seems that in THREE.AnimationHandler, data.hierarchy is undefined, so I'm guessing that if I can somehow make it defined, the problem will be fixed. Except I don't know how, or even why it is not defined. Any help?
You are passing only the animation's name, not the whole data object. Use this instead:
this.animation = new THREE.Animation(this.mesh, this.mesh.geometry.animations[0]);

Having IE Issues When Passing Object By Ref. and Dynamically Adding Properties

So, I've created a function to do some error checking on an XML file that I recieve from an AJAX call. Part of the validation is that the function then builds out an object for easy access while I process that data into a form. In FF, works like a charm. IE dies with the error:
Object doesn't support this property or method
Here is the function (minus the un-important bits):
function checkReceiveXMLTagString( doc, messageObject, tag ) {
var tag_nodes = doc.getElementsByTagName( tag );
...do some error checking...
messageObject[tag] = tag_str; <-- error occurs on this line
return true;
}
Here is an example of how the function is call:
if ( checkReceiveXMLTagString( messageObject.Name[0], messageObject.Name[0], "First" ) ) {
...process messageObject.Name[0].First...
}
Like I said, FF has no issues. Safari loads the pages as well. IE has issues.
Thanks!
Looks like something is making messageObject be null or undefined
If the error is on this line:
messageObject[tag] = tag_str;
Then, the only two ways I know of that that can cause an error are:
messageObject is not an object that you can set properties on (null or undefined are the most likely ways that would happen)
tag is null or undefined
Since I see that your code calls this function hundreds of times so you can't effectively just break on it, I'd suggest you put in some defensive coding to check for those conditions and output something to the debug console to identify what the state is when the problem occurs. You can even trigger a conditional breakpoint with code like this:
if (!messageObject || !tag) {
debugger;
}
In the toughest cases, you can put an exception handler around it and break when the exception is thrown:
try {
messageObject[tag] = tag_str;
} catch(e) {
debugger;
}
Both of these will allow you to capture the condition in the debugger and examine all your parameters at the time of the error.

Categories