Javascript-style DOM manipulations of the HTML document seem to take effect only after running the entire PyScript code. Example:
<div id="progress"></div>
<py-script>
# Some code
js.document.getElementById("progress").textContent = "Continuing with the next computations..."
# Some more code
</py-script>
This may not be problematic in many cases, but my PyScript code takes several minutes to finish and I am using DOM manipulation as a way to inform users of the progress.
Is there any way to update the DOM immediately in PyScript?
More information is required to determine how to handle your situation. But here's an example of running async python code in py-script if it helps.
<head>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head>
<body>
<p id="progress">Progress bar placeholder</p>
<py-script>
import asyncio
async def updateText(i):
js.document.getElementById("progress").textContent = f"Running... {i}"
print(i)
await asyncio.sleep(1)
async def main():
for i in range(10):
await updateText(i)
asyncio.ensure_future(main())
</py-script>
</body>
Related
So I noticed that in my _Host.cshtml file I have this script before the </body> tag
<script src="_framework/blazor.server.js"></script>
And I also have some scripts that are suppose to load after that which are these
<script src="assets/plugins/jquery/jquery.min.js"></script>
<script src="assets/plugins/jquery-ui/jquery-ui.js"></script>
<script src="assets/plugins/popper/popper.js"></script>
<script src="assets/plugins/feather/feather.min.js"></script>
<script src="assets/plugins/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/plugins/typeahead/typeahead.js"></script>
<script src="assets/plugins/typeahead/typeahead-active.js"></script>
<script src="assets/plugins/pace/pace.min.js"></script>
<script src="assets/plugins/slimscroll/jquery.slimscroll.min.js"></script>
<script src="assets/plugins/highlight/highlight.min.js"></script>
<!-- Articles Script -->
<script src="assets/plugins/dataTable/datatables.min.js"></script>
<script src="assets/plugins/summernote/summernote.min.js"></script>
<script src="assets/plugins/bootstrap-tagsinput/bootstrap-tagsinput.js"></script>
<!-- Required Script -->
<script src="assets/js/app.js"></script>
<script src="assets/js/avesta.js"></script>
<script src="assets/js/avesta-customizer.js"></script>
</body>
However, if I have the blazor.js script at the top, my menu won't act normal, it will stop working and look like this.
I'm actually clicking a lot and it's not animating as you can see.
However if I put the blazor.server.js script at the bottom to load last, it works just fine and looks like this
But then if I load it last, I get this in my console
which results in my not being able to do this
<input #bind="#CurrentValue" #oninput="#((e) => { CurrentValue=(string)e.Value;})" #onkeypress="KeyPress" class="form-control" type="text" placeholder="Search" aria-label="Search">
It just doesn't hit the function at all, nothing happens, it doesnt register it.
Using the Net5, You can now reference your scripts on the main layout by overriding the OnAfterRenderAsync. Here is an example
You will first inherit IJSRuntime
#inject IJSRuntime JSRuntime
Then here is the Code:
#code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if(firstRender)
{
await JSRuntime.InvokeAsync<IJSObjectReference>("import", "/assets/plugins/jquery/jquery.min.js");
}
}
}
Can you guys if possible share screen shot or show how you added JavaScript Libraries Reference in project to make it work and Where (e.g. MainLayout.razor or _Host.cshtml) also where you guys added blazor.server.js
I tried both ways adding JavaScript references in _Host.cshtml file before tag like following. But it didn't worked.
<script src="~/_framework/blazor.server.js"></script>
<script src="~/plugins/global/plugins.bundle.js"></script>
<script src="~/plugins/custom/prismjs/prismjs.bundle.js"></script>
<script src="~/js/scripts.bundle.js"></script>
<script src="~/plugins/custom/fullcalendar/fullcalendar.bundle.js"></script>
<script src="~/js/custom/widgets.js"></script>
<script src="~/js/pages/custom/wizard/wizard-5.js"></script>
Then I added as you suggested in last comments under MainLayout.razor page even that didn't worked. For MainLayout please see following (In this case If I inspect page element it is not showing any JavaScript References in Page Tags.
#code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JSRuntime.InvokeAsync<IJSObjectReference>("import", "_framework/blazor.server.js");
await JSRuntime.InvokeAsync<IJSObjectReference>("import", "/plugins/global/plugins.bundle.js");
await JSRuntime.InvokeAsync<IJSObjectReference>("import", "/plugins/custom/prismjs/prismjs.bundle.js");
await JSRuntime.InvokeAsync<IJSObjectReference>("import", "/js/scripts.bundle.js");
await JSRuntime.InvokeAsync<IJSObjectReference>("import", "/plugins/custom/fullcalendar/fullcalendar.bundle.js");
await JSRuntime.InvokeAsync<IJSObjectReference>("import", "/js/pages/widgets.js");
await JSRuntime.InvokeAsync<IJSObjectReference>("import", "/js/pages/custom/wizard/wizard-5.js");
}
}
}
Note: I also tried with ~/ or / or ../ just before library path but didn't worked for me.
It's not a complete solution (at least for me yet) as it's causing all sorts of racing conditions - but seems like I'm on the correct path of solving this - hopefully some time within the next decade.
Seems like one of the nicer ways of doing this is disabling the autostart on blazor.server|webassembly.js link, and then adding the JS file imports by adding them as elements.
<script src="_framework/blazor.server.js" autostart="false"></script>
After this, create a below your blazor import, and import your elements to the page. You will see them being added to the page after Blazor is loaded. Excuse the dirty code, it's WIP and I'm still experimenting.
<script>
Blazor.start().then(function () {
var customScript = document.createElement('script');
customScript.setAttribute('src', 'assets/plugins/global/plugins.bundle.js');
document.body.appendChild(customScript);
var anotherScript = document.createElement('script');
anotherScript.setAttribute('src', 'assets/js/scripts.bundle.js');
document.body.appendChild(anotherScript);
});
</script>
If you don't add the autostart="false" attribute, you'll see an error message in console, saying that the Blazor has already started.
My understanding is that await JSRuntime.InvokeAsync<Iblah>("import", "blah.js"); is meant for Razor components, but correct me if I'm wrong. If anyone wonders, I'm using Metronic, not that it matters.
According to the docs, all I need to do is to wrap the block I'd like to "talk to" via Javascript with this:
<amp-script layout="container" src="language-toggle.js">
// Some basic HTML
</amp-script>
The Javascript file is there, I tested with a simple console.log. Yet the amp-script tag has opacity: 0.7 (AMP default style). Apparently, it needs the class i-amphtml-hydrated to be fully visible. I've been trying to wrap my head around this for a few hours now, even Google could not help me with this.
There are a bunch of ServiceWorker errors in the console, which are also all generated by AMP. I have no idea why they appear or how to get rid of them. This whole AMP thing is a mess for me.
These are the AMP scripts I currently added:
<script async src="https://cdn.ampproject.org/v0.js"></script>
<script async custom-element="amp-script" src="https://cdn.ampproject.org/v0/amp-script-0.1.js"></script>
<script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
<script async custom-element="amp-youtube" src="https://cdn.ampproject.org/v0/amp-youtube-0.1.js"></script>
Carousel and YouTube are working fine.
Could anybody please shed some light onto this?
I highly recommend to enable AMP development mode by adding #development=1 to the URL.
Relative URL's are not allowed in the src attribute of the amp-script tag (the development parameter would have told you that).
You can have something like this though:
<amp-script width="1" height="1" script="demo"></amp-script>
<script type="text/plain" target="amp-script" id="demo">
console.log('Foobar');
</script>
But you will need a matching hash in a meta tag in your head:
<head>
...
<meta
name="amp-script-src"
content="sha384-hash"
/>
</head>
Again, the development parameter will tell you the hash you should use, although you could also disable hash checks during development.
All of the above will still not hydrate your amp-script element. In order for your element to be hydrated, the script has to actually to something to the DOM, like for example adding a div on a button click:
<amp-script layout="container" script="demo">
<button id="hello">Add headline</button>
</amp-script>
<script type="text/plain" target="amp-script" id="demo">
console.log('Foobar');
const button = document.getElementById('hello');
button.addEventListener('click', () => {
const h1 = document.createElement('h1');
h1.textContent = 'Hello World!';
document.body.appendChild(h1);
});
</script>
Be aware that you are quite limited with what you are allowed to do. For example, the above snippet will not work without the event listener, so you can not simply add an element without user interaction.
The messages regarding the references can safely be ignored - the AMP examples do exaclty the same, the AMP still passes the validation.
I want to execute some JS library in RSpec.
for example
I can execute "Payment Library" of JavaScript Library in HTML like below.
<!DOCTYPE html>
<html>
<head>
<script src="https://sample.example/payment.js"></script>
</head>
<body>
<div id="foo"></div>
</body>
<script>
$(document).ready(function(){
// Payment depends on "https://sample.example/payment.js"
Payment.init("11111");
Payment.getToken({cardNo: "1111111111111111", expired: "2001"});
});
</script>
</html>
Is it possible to load external JavaScript Library like using "script" tag in RSpec like this.
js_code = <<'EOS'
{
<script src="https://sample.example/payment.js"></script>
Payment.init("11111");
Payment.getToken({cardNo: "1111111111111111", expired: "2001"});
}
EOS
ExecJS.eval js_code
Pleas give me any advice.
Thanks.
A good read, recent enough to take it into account : https://robots.thoughtbot.com/headless-feature-specs-with-chrome
Basically, it'll wait for your js (the one you included in your pages) to finish execute before validating your tests. This is what you want.
From there, it'd be advisable to avoid any js injections (even if it is available), and then rely entirely on the headless browser setup
I'm developing a web application that because of performance concerns is heavily reliant on Ajax functionality. I'm attempting to make parts of each page available while longer running modules load.
The issue is that I want to kick off the Ajax requests as soon as possible (in the head of the document). This part works fine; the issue is on rare occasion, the Ajax call will come back before the area that I want to load the Ajax data into is present on the page. This causes the data to not be loaded.
To get around the issue I started using script tags below each of my containers that resolve a JQuery promise to let the code know that the area is available.
EDIT: I want to load the data into the area as soon as it becomes available (before full document load).
The current pseudo code looks like this:
<head>
<script>
var areaAvailablePromise = new $.Deferred();
$.when(areaAvailablePromise, myAjaxFunction()).then(function(){
// load data into the element.
});
</script>
</head>
<!-- much later in the document -->
<div class="divIWantToLoadAjaxContentInto"></div>
<script>
areaAvailablePromise.resolve();
</script>
My question is: is there ANY better way to handle this situation? Every one knows that inline scripts are blocking and are bad for performance. Also, I feel that this is going to lead to cluttered code with micro-script tags all over the place.
Put your (whole) <script> tag just after the element.
HTML is parsed from top to bottom, so the element will be loaded already.
No. There really is no better way to my knowledge.
<!doctype html>
<html>
<head>
<script src="jquery.min.js"></script>
<script src="q.min.js"></script>
<script>
var elD = Q.defer();
var dataP = Q($.ajax(…));
Q.spread([elD.promise, dataP], function (el, data) {
…
}).done();
</script>
</head>
<body>
…
<div id="foo"></div>
<script>elD.resolve($("#foo"));</script>
…
</body>
</html>
you can use:
$(document).ready( handler )
(recommended)and also has contracted form:
$(handler)
exemple:
$(function(){
alert("OK");
})
read more: http://api.jquery.com/ready/
I observed number of instruction counts executed on cpu while running javascript tests on Android browser.
The test js codes are simple in html. The files are in android local directory, not in webserver.
In html:
<html>
<head>
<script type='text/javascript' src='test.js'>
</head>
<body>
<div id='content'> ... </div>
<span> .. </span>
<div id='logo'> ... </div>
...
</body>
</html>
In test.js:
for (i = 0; i < 1000 ; i++) {
...
$().append("<div id='content2'> ... </div>
var temp1 = $(span#content2)
var temp2 = $(#logo)
var temp3 = $(h3.id)
...
}
In a nutshell, in test.js, simple methods such as .append() using jQuery are used.
When I run this simple test code on Android browser, I think I should have consistent number of the instructions, but, actually, I have various instruction counts in each run.
It may have some pattern in the variation, but, not seem clear.
My initial guess was an "asynchronous" thing in DOM in html with javascript.
So, I changed the html like this:
<html>
<head>
</head>
<body>
<div id='content'> ... </div>
<span> .. </span>
<div id=''> ... </div?
...
</body>
<script type='text/javascript' src='test.js'>
</html>
Also, I tried this
$(document).ready(function() {
...
$().append("<div id='content2'> ... </div>
var temp1 = $(span#content2)
var temp2 = $(#logo)
...
});
But, I didn't get consistent number of instructions yet.
This is caused by asynchronous problem? Or jQuery methods in terms of DOM have kinda indeterministic behavior in run time? Or, JS JIT compiler has very different behavior in each run? Can anyone give me some clue?
Thanks!
It's not just that JavaScript does not run synchronously with DOM rendering, it's that HTML parsing itself is inherently loose, and was never designed to be deterministic. "Good enough" is what got JavaScript and HTML to where every device and its brother can use them, but the price paid for that is some level of unpredictability.
In general, don't use HTML parsing if you don't have to, especially if you want consistent performance. The DOM has a perfectly serviceable createElement method that you can send to jQuery's append method, which will likely get you more consistent results. (And it's not like insertBefore is all that hard a method to use. If you're taking the time to measure CPU cycles, you're doing a level of work significantly greater than jQuery's target model.)
(And I'd be very surprised if a JIT compiler didn't give you different results over a large enough test run. Unless you manage to have exactly the same device each time, I'd expect some variation based on the available input variables it would have to use to judge how much compilation to do, such as memory allotment and CPU load.)