Dojo timing issue with dijit/registry and dojo/domReady - javascript

I am working on a one-page application in Dojo which submits forms via ajax and returns parses the return value before rendering the page. When I go about this I end up with a timing error.
When the following code is included via a script tag, it logs undefined:
require(["dijit/registry", 'dojo/domReady!'], function(registry){ console.log(registry.byId('my-id')) });
When I paste it in the console, I get the expected dijit widget.
I suspect that the problem is that this is firing before the page is rendered. Is there an easy way to ensure that this happens after the current document has been fully parsed and included in the main window?

May be you should try, to add Parser and call the Parser.parse() before trying to access the widget.
This is from Dojo documentation
Note that waiting for dojo/domReady! to fire is often not sufficient
when working with widgets. Many widgets shouldn’t be initialized or
accessed until the following modules load and execute:
dojo/uacss
dijit/hccss
dojo/parser

Related

How to prevent Google Tag Manager overwriting document.write()?

We are using Angular for our Website. As not all Pages have been ported to Angular, we implemented a hybrid approach:
Every request goes to Angular first. When it has been loaded, it checks if the Route exists
If not, the HTML-page is fetched from the backend
The html-Element in the DOM (i.e. the complete page) is replaced with the response's body
ngOnInit() {
this.railsService.fetchRailsPage(this.router.url).subscribe(
(response) => this.replaceDOM(response),
(errorResponse) => this.replaceDOM(errorResponse.error)
);
}
private replaceDOM(newContent: string) {
document.open();
document.write(newContent);
document.close();
}
Since all a-hrefs in old pages are plain old hrefs (not Angular's routerLinks), once the user navigates away, the page is reloaded and Angular kicks in again.
So far, it works, but: I noticed that sometimes the DOM is not replaced with the response body.
Debugging brought us to the conclusion that Google Tag Manager could be the issue. It overwrites document.write() and a lot of other default Javascript functions.
Why is that? And how can this be prevented to get the default version of e.g. document.write()?
Seconding Alan here.
Please make sure you're running two tests:
Block gtm with the request blocking function of the dev tools and try reproducing the issue.
Try creating an empty GTM container, loading it on page and reproduce the issue.
If the first test shows that The issue persists with GTM blocked, then it's not GTM.
If the second test shows that the issue is solved, then it's not about GTM but about the logic used in it's configuration.
If anything, I would first make sure no custom code in GTM additionaly overrides document.write (which I've never seen before, but it's definitely possible). Then I would broadly audit all custom scripts deployed by GTM. After that, I would try pausing all the element visibility triggers if any are deployed and seeing if that helps.
GTM likely would aim to override write to be able to watch DOM changes. But it does so gently, adding a bit of tracking there and not changing the essence of it. It's severely unlikely that GTM's core logic would conflict with Angular.
//UPD just had a chat with a colleague on Measure. It looks like the only scenario when GTM overrides the document.write is when there are Custom HTML tags that have an option to "support document.write". The Element Visibility trigger uses mutation and intersection observers rather than listening to document.writes.

Event listener works in on context but not another - code identical, and no errors observed. Possible causes?

I'm bamboozled. I use a select2 widget on a web page, implemented by django-autocomplete-light, and I attach an event listener to the it as follows:
const game_selector = $("#"+id_prefix+"game");
game_selector.on("change", switchGame);
Works a charm. I select a new game in the select box and the switchGame function is called.
That is running on Django development server with manage.py runserver. And I can see how groovy this is in Chrome's debugger:
There it is, switchGame(event) is the handler. And it all works too. No drama.
But I publish the code to my webserver and suddenly it doesn't work. The event listener never fires. switchGame is never called.
It's serving the self same code, looks the same in the client and in Chrome's debugger. All fine. I can even see the event listener is attached, albeit the order is different:
Served by the development server there there is a select2 handler above switchGame in the list and served from the production server the same select2 handler is listed below the switchGame handler.
Can the order matter? And why would the order differ?
In the end I am looking at the same binding code above, and I can set a breakpoint inside switchGame and cI can confirm served by the django runserver switchGame runs when I select a new game, but served from the production server it does not.
Suspect some jquery issue I even changed the listener binding to:
const game_selector = $("#"+id_prefix+"game");
//game_selector.on("change", switchGame);
game_selector.get(0).addEventListener("change", switchGame);
But the behaviour is the same. Bamboozles me how Javascript might function differently based on the server context? leads me to suspect different Javascript being served, but every check I have made speaks against that, as in I can make an edit, publish and reload web page from productions server and the changed javascript is there and visible in Chrome's debugger.
I wonder if anyone has ever experience such bizarre behaviour before and is in a position to comment or to suggest further diagnostic directions.
This is a nasty side effect of loading the jQuery library twice.
I was loading it explicitly and a widget I was using loaded it again implicitly. A bug!
Discussed in depth here:
github.com/yourlabs/django-autocomplete-light/issues/1079
and not yet fixed, but workaround is that I don't load jQuery explicitly any more. And the issue disappears.
Sadly this does not explain the symptoms very well but it does provide a solution to what was being experienced. The same code was running in two contexts working in one and not the other. Remove the jQuery reload and it works in both.

Webextension inline install chrome.runtime.connect issues

I'm having a really weird issue, I've developped a webextension that uses messaging between content script and background script (using chrome.runtime.connect) and nativemessaging.
The issue i'm facing is that when I install the extension (manually from the store beforehand and then connect to my website, everything works as expected, the chrome.runtime.connect works and returns a valid port to the background script.
But when i do an inline install of the extension from my website to get around the fact to have to navigate to have the content script in the webpage, i manually inject the content script into my page using
function injectContentScript() {
var s = document.createElement("script");
s.setAttribute("src", "chrome-extension://<extensionid>/content.js");
document.head.appendChild(s);
}
and the exact same content script but manually injected doesn't behave the same. chrome.runtime.connect returns a null object and chrome.runtime.lastError gives me
Could not establish connection. Receiving end does not exist.
I'm calling on the sender side (content.js - manually injected content script) chrome.runtime.connect(extensionID) where extension id is the id of the extension generated by the chrome webstore. And on the receiving side (background.js - extension background script) chrome.runtime.onConnect.addListener(onPortConnected);
I'm not really sure how to debug this issue, maybe it's a timing issue?
The background script is well executed even with the inline install (i've added logs and debugged it through the background.html in chrome extension manager)
Any help would be greatly appreciated!
You have two scenarios.
Your content script content.js is executed as normal upon navigation, as a content script defined in the manifest.
In this case, it executes in a special JS context attached to the page and reserved for your content scripts. See Execution Environment docs section for explanation. It is isolated from the webpage and is considered part of the extension (albeit with lower privileges).
When you connect from a content script, chrome.runtime.connect() is treated as internal communication between parts of the extension. So while you can provide the extension ID, it is not needed.
More importantly, the event raised in this case is chrome.runtime.onConnect.
Your supposed "inject content script immediately" code called from the webpage does something completely different.
Instead of creating a new execution context, the code is instead added directly to the page; it is not considered part of the extension and has no access to extension API.
Normally, a call to chrome.runtime.connect() would simply fail, as this is not a function exposed to webpages; however, you also declared externally_connectable, so it is exposed specifically to your webpage.
In this case, passing the extension ID is mandatory for the connect. You were doing this already, so the call was succeeding.
However, and that's what made it fail: the corresponding event is no longer onConnect, but onConnectExternal!
What you should be doing is:
Not mixing code that is run in very different contexts.
If you need communication from the webpage to background, always do it from the webpage, not sometimes-from-content-sometimes-from-page.
That way you only have to listen to onConnectExternal and it cuts out the need for a content script (if it was its only function).
See the docs as well: Sending messages from web pages.
You don't have to source the code from chrome-extension://<extensionid>/; you can directly add this to your website's code and potentially avoid web_accessible_resources.
And if you actually want to inject content scripts on first run, see for example this answer.
Related reading: How to properly handle chrome extension updates from content scripts

Javascript in asp.net MVC... Beginner issue

I created an Asp.Net MVC Internet Aplication and in my Index view of the Home Controller I have this
This is the first line, before the script results.
<script type="text/javascript" src="~/Script/Teste.js"></script>
<br />
This line comes after the script.
In my Teste.js I have this:
document.write("Yes! I am now a JavaScript coder!");
But nothing happens. If I change the src attribute and put some random name src="aaaa", despite the fact "aaaa" doesnt exist, I get no error in runtime.
EDIT
Also, check your path again. The default MVC templates in VS create a folder called Scripts, not Script. ("~/Scripts/teste.js")
Per the comment below, this was not the root cause of the issue, but in other cases can easily bite new JavaScript developers.
Most likely, your document.write function is firing before the document is ready, leading to the appearance that nothing is happening. Try the following in your Teste.js file
window.onload = function ()
{
document.write("Yes! I am now a JavaScript coder!");
//or even better as a test
alert("This alert was called");
}
Check the source of your page as well, it could be the document is being written to, you just can't see it due to markup/page styling.
As for you second issue, there will be no 'Runtime Exception' thrown if you reference a non-existent file. If you are using tools like Firebug or Chrome's developer tools, you should see a request to http://siteDomain/Scripts/aaaa.js with a response of 404, not found.
You generally should avoid using document.write() unless you absolutely have to use it for some reason... I don't think I've ever come across such a situation, and write a lot of Javascript.
Try this:
1) Put this in your HTML:
<script src="/scripts/teste.js"></script>
2) Put this in your JS:
alert('Yes! I am now a JavaScript coder!');
3) Open Chrome since it makes it easy to look for external resources loading and open the Network tab in Developer Tools (click the menu button at top-right, Tools > Developer Tools, Network tab).
4) Run your project and copy/paste the URL in the browser that comes up into this Chrome window, and hit enter.
When your page loads one of 2 things will happen:
A) You'll get the alert box you wanted or
B) You'll find out why it isn't loading because the Network tab will show the browser attempting to fetch teste.js and failing in some fashion, for example a 404, which would indicate you've got a typo in the path, or the script isn't where you thought it was, etc.
Put the following line at the very end of your document. There should not be anything after. Then try to load the page.
<script type="text/javascript" src="~/Script/Teste.js"></script>
Also, try pressing F12 once the page loads to see the source. Check if you script is there.
In MVC, the tilde is used to refer to the root URL of your application. However, it cannot normally parse this information. If you write:
<script src="~/Script/Teste.js"></script>
The lookup will fail, because the ~ means nothing special in HTML. If you're using Razor as your view engine (not ASPX), you need to wrap that call in Url.Content like so:
<script src="#Url.Content(~/Script/Teste.js)"></script>
Doing this will ensure a valid URL is provided to the browser.
With that in mind, you need to check that you have the file name and folder name both correct. You also need to ensure that the file is being deployed with your application. You can do this my opening the properties panel while the file is selected in the Solution Explorer and pressing F4.

forcing page load on an AJAX-loaded page

I have an issue with an third-party integration on an iPad-specific website, which has a number of pages loaded via AJAX.
When I go to the page for the first time the functionality that is expected to be available is not, and only when I do a page refresh in Safari do I see the feature.
In the 3rd party JavaScript there is this sort of code peppered throughout:
script.onload = script.onreadystatechange = function () { // do something }
Here is the full JavaScript included file.
Is there a way that I can either force a page load on the iPad or build in some workaround that means that when I change to the page where the JavaScript is included and fires?
As I mentioned, this is only apparent on an iPad-specific website and the same feature has no problem on a desktop browser where the page is not loaded via AJAX.
i believe web servers allow you to add content dynamically for all pages rendered using the web server. which allows you to insert a code snippet which can ideally check if its a ipad website and do page load as you requested.
follow the below thread
http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/e27f918e-89a9-45a8-8604-2ad2ded09d64.mspx?mfr=true
I have no idea what your code looks like, but, having experienced the same issues repeatedly with jQuery, I would suggest you manually call the initialize function of the 3rd party script within a window ready state function:
$(window).ready(function(e) {
// function that initializes the 3rd party script gets called here.
});

Categories

Resources