I am making a feed reader in Visual Studio using JavaScript, and when I run it, I get an error:
0x800a138f - JavaScript runtime error: Unable to get property 'addEventListener' of undefined or null reference
and the code that is affected is:
articlelistElement.addEventListener("iteminvoked", itemInvoked);
articleListElement refers to a variable that references a WinJS.UI.Listview.
Thanks for your help!
If your document.getElementById("articlelist") is returning null, then you must be attempting to add the listener before the DOM is actually loaded.
If you started with the Blank project template, then in default.js you'll see this code:
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
args.setPromise(WinJS.UI.processAll());
}
};
Until this activated event is called, the DOM won't be ready and getElementById can return null. (For a full run-down of the activation sequence, see Chapter 3 of my free ebook, Programming Windows Store Apps with HTML, CSS, and JavaScript).
If you're using the Navigation or Grid app templates, then you need to place that initialization code inside the page control's ready method (or the processed method). With the Navigation template, you'll see that code in pages/home/home.js. (The same chapter of my free ebook talks about page controls.)
That's the first step--if you're calling getElementById at the right time, then it should give you back the div where you declare the ListView.
There's more to the story, however, because to attach an event handler properly to a WinJS control, you have to make sure that control has been instantiated. This is the purpose of WinJS.UI.processAll in the Blank template code above (the same call is also made automatically as part of loading a page control).
WinJS.UI.processAll (or WinJS.UI.process, which works in an individual element and its children rather than the whole document), goes through the DOM looking for data-win-control attributes. When it finds one, it parses the data-win-options attribute (if you provide one), and then calls the constructor identified in data-win-control with that parsed options object.
Until that happens, the where you declare the control will just be a div and not contain any other control structure.
With page controls, again, within the processed or ready methods the controls should be instantiated. In the Blank template, you need to attach a completed handler to WinJS.UI.processAll:
args.setPromise(WinJS.UI.processAll().then(function () {
//Controls have been instantiated, do initialization here
//Note that calling .then and not .done is necessary because we need to return a promise
//to args.setPromise.
});
At that point, then, document.getElementById("articlelist") should get you to the ListView's host div.
The last step is that to attach a handler to a WinJS control event, you have to add the listener to the control object not the host div, which you get through the .winControl property of that host element. So your code needs to look like this:
articlelistElement.winControl.addEventListener("iteminvoked", itemInvoked);
Related
I am new to JavaScript and Odoo. Whenever I open the JavaScript files of the base modules, I see init, start, sometimes, render_value. What are these things for. Thanks.
Hello Jeremy Gillbert,
You can reffered this document Click here
Start = > Basically the Start of an application JavaScript, where the code begins to be executed, is when is called the method window.OnLoad, after the page, is fully loaded, and automatically call it method, there exist others way to call code from the page.
Init = > init is just shorthand for the initiate. Typically it is used to create a "new Object()" with return the same.
render_value => render_value means,To grab an input value with javascript and render it into a div or particular element.
Thanks
I am trying to implement the displaying of a web page in Qt. I chose to use the Qt WebEngine to achieve my task. Here's what I did :
Wrote a sample web page consisting of a empty form.
Wrote a JS file with just an API to create a radio button inside the form.
In my code, it looks like this :
View = new QWebEngineView(this);
// read the js file using qfile
file.open("path to jsFile");
myJsApi = file.Readall();
View->page()->runjavascript (myjsapi);
View->page()->runjavascript ("createRadioButton(\"button1\");");
I find that the runJavaScript() function has no effect on the web page. I can see the web page in the output window, but the radio button I expected is not present. What am I doing wrong?
I think you will have to connect the signal loadFinished(bool) of your page() to a slot, then execute runJavaScript() in this slot.
void yourClass::mainFunction()
{
View = new QWebEngineView(this);
connect( View->page(), SIGNAL(loadFinished(bool)), this, SLOT(slotForRunJS(bool)));
}
void yourClass::slotForRunJS(bool ok)
{
// read the js file using qfile
file.open("path to jsFile");
myJsApi = file.Readall();
View->page()->runJavaScript(myjsapi);
View->page()->runJavaScript("createRadioButton(\"button1\");");
}
I had this problem, runJavascript didn't have any effect. I had to put some html content into the view (with page().setHtml("") before running it.
Check the application output, it might contain JavaScript errors. Even if your JS code is valid, you might encounter the situation where the script is run before DOMContentLoaded event, that is document.readyState == 'loading'. Therefore, the DOM might not be available yet, as well as variables or functions provided by other scripts. If you depend on them for your code to run, when you detect this readyState, either wait for the event or try calling the function later, after a timeout. The second approach with timeout might be needed if you need to get the result of the code execution, as this can be done only synchronously.
Previously I've put working webcam code into my application, but now it's not working when I updated to AngularJS v1.5.0. I am using webcam-directive which was working perfectly with v1.3.0.
Here is my code:
<webcam placeholder="selfiePlaceHolder"
on-stream="onStream(stream)"
on-access-denied="onError(err)" on-streaming="onSuccess(video)">
</webcam>
But now it's giving following error with AngularJS v1.5.0:
Uncaught Error: [$parse:isecdom] Referencing DOM nodes in Angular expressions is disallowed! Expression: onSuccess(video)
http://errors.angularjs.org/1.5.0/$parse/isecdom?p0=onSuccess(video)
I also tried to use a different solution with AngularJS ng-Camera but even its demo page is not working for me.
Note: I know the issue is that we can't access the DOM from the newer version of AngularJS, but the same code works with the older version. I need to know how to pass the "Video" DOM object to the controller.
I've found the solution to the problem. Two things need to be done:
First In HTML:
<webcam channel="channel"
on-streaming="onSuccess()"
on-error="onError(err)"
on-stream="onStream(stream)"></webcam>
Secondly, in the controller, you can access the DOM video with the following code:
$scope.onSuccess = function () {
// The video element contains the captured camera data
_video = $scope.channel.video;
$scope.$apply(function() {
$scope.patOpts.w = _video.width;
$scope.patOpts.h = _video.height;
//$scope.showDemos = true;
});
};
Here is a working example.
It is a potential error generally occurs when an expression tries to access a DOM node since it is restricted accessing to DOM nodes via expressions by AngularJS because it might cause to execute arbitrary Javascript code.
The $parse:isecdom error is related to an invoke to a function by event handler when an event handler which returns a DOM node, like below:
<button ng-click="myFunction()">Click</button>
$scope.myFunction = function() {
return DOM;
}
To fix this issue, avoid access to DOM nodes and avoid returning DOM nodes from event handlers. (Reference: https://docs.angularjs.org/error/$parse/isecdom)
Adding an explicit return might solve this issue as detailed here: CoffeeScript - Referencing DOM nodes in Angular expressions is disallowed
I was able to get webcam-directive working using the channel suggestion from the comment above, based on the example on the github page.
function MyController($scope) {
$scope.myChannel = {
// the fields below are all optional
videoHeight: 800,
videoWidth: 600,
video: null // Will reference the video element on success
};
}
In the onSuccess(on-streaming attr) and onStream(on-stream attr) callback the video property of myChannel was filled in with the video DOM element (and then it would obviously be available to everything else in the controller too). According to the comment in the example code though, you should wait to access it at least until onSuccess. Here is a working example
I've had this happen in Chrome and IE...
If I click a link to navigate away from a page while requirejs is still loading or getting scripts, I get random errors. Sorry if this is vague...
For example, in require.js itself, I received an error today:
Unable to get value of the property 'normalize': object is null or undefined
In the following block:
//If current map is not normalized, wait for that
//normalized name to load instead of continuing.
if (this.map.unnormalized) {
//Normalize the ID if the plugin allows it.
if (plugin.normalize) {
name = plugin.normalize(name, function (name) {
return normalize(name, parentName, true);
}) || '';
}
//prefix and name should already be normalized, no need
//for applying map config again either.
normalizedMap = makeModuleMap(map.prefix + '!' + name,
I've received other errors in my own defined js files where they start executing the code before the dependencies are fully loaded. I get the feeling that when the browser is asked to navigate away from the current page, it stops all ajax calls and thus truncating some of the js.
Is there a way to prevent these sort of errors?
Avoid running code in the define function's scope. Start your app's logic once everything has loaded by writing your code in functions that get executed when your page is ready.
Also what do you mean by navigate? If you navigate away the page goes away, as well as its errors. Is this pushAPI style navigation with the app staying loaded, or a complete and full browser navigation?
Taking Jeff Atwood's advice, I decided to use a JavaScript library for the very basic to-do list application I'm writing. I picked the Dojo toolkit, version 1.1.1. At first, all was fine: the drag-and-drop code I wrote worked first time, you can drag tasks on-screen to change their order of precedence, and each drag-and-drop operation calls an event handler that sends an AJAX call to the server to let it know that order has been changed.
Then I went to add in the email tracking functionality. Standard stuff: new incoming emails have a unique ID number attached to their subject line, all subsequent emails about that problem can be tracked by simply leaving that ID number in the subject when you reply. So, we have a list of open tasks, each with their own ID number, and each of those tasks has a time-ordered list of associated emails. I wanted the text of those emails to be available to the user as they were looking at their list of tasks, so I made each task box a Dijit "Tree" control - top level contains the task description, branches contain email dates, and a single "leaf" off of each of those branches contains the email text.
First problem: I wanted the tree view to be fully-collapsed by default. After searching Google quite extensively, I found a number of solutions, all of which seemed to be valid for previous versions of Dojo but not the one I was using. I eventually figured out that the best solution would seem to be to have a event handler called when the Tree control had loaded that simply collapsed each branch/leaf. Unfortunately, even though the Tree control had been instantiated and its "startup" event handler called, the branches and leaves still hadn't loaded (the data was still being loaded via an AJAX call). So, I modified the system so that all email text and Tree structure is added server-side. This means the whole fully-populated Tree control is available when its startup event handler is called.
So, the startup event handler fully collapses the tree. Next, I couldn't find a "proper" way to have nice formatted text for the email leaves. I can put the email text in the leaf just fine, but any HTML gets escaped out and shows up in the web page. Cue more rummaging around Dojo's documentation (tends to be out of date, with code and examples for pre-1.0 versions) and Google. I eventually came up with the solution of getting JavaScript to go and read the SPAN element that's inside each leaf node and un-escape the escaped HTML code in it's innerHTML. I figured I'd put code to do this in with the fully-collapse-the-tree code, in the Tree control's startup event handler.
However... it turns out that the SPAN element isn't actually created until the user clicks on the expando (the little "+" symbol in a tree view you click to expand a node). Okay, fair enough - I'll add the re-formatting code to the onExpand() event handler, or whatever it's called. Which doesn't seem to exist. I've searched to documentation, I've searched Google... I'm quite possibly mis-understanding Dojo's "publish/subscribe" event handling system, but I think that mainly because there doesn't seem to be any comprehensive documentation for it anywhere (like, where do I find out what events I can subscribe to?).
So, in the end, the best solution I can come up with is to add an onClick event handler (not a "Dojo" event, but a plain JavaScript event that Dojo knows nothing about) to the expando node of each Tree branch that re-formats the HTML inside the SPAN element of each leaf. Except... when that is called, the SPAN element still doesn't exist (sometimes - other times it's been cached, just to further confuse you). Therefore, I have the event handler set up a timer that periodically calls a function that checks to see if the relevant SPAN element has turned up yet before then re-formatting it.
// An event handler called whenever a "email title" tree node is expanded.
function formatTreeNode(nodeID) {
if (dijit.byId(nodeID).getChildren().length != 0) {
clearInterval(nodeUpdateIntervalID);
messageBody = dijit.byId(nodeID).getChildren()[0].labelNode.innerHTML
if (messageBody.indexOf("<b>Message text:</b>") == -1) {
messageBody = messageBody.replace(/>/g, ">");
messageBody = messageBody.replace(/</g, "<");
messageBody = messageBody.replace(/&/g, "&");
dijit.byId(nodeID).getChildren()[0].labelNode.innerHTML = "<b>Message text:</b><div style=\"font-family:courier\">"+messageBody+"</div>";
}
}
}
// An event handler called when a tree node has been set up - we changed the default fully-expanded to fully-collapsed.
function setupTree(theTree) {
dijit.byId("tree-"+theTree).rootNode.collapse();
messageNode = dijit.byId("tree-"+theTree).rootNode.getChildren();
for (pl = 0; pl < messageNode.length; pl++) {
messageNode[pl].collapse();
messageNode[pl].expandoNode.onclick = eval("nodeUpdateIntervalID = setInterval(\"formatTreeNode('"+messageNode[pl].id+"')\",200); formatTreeNode('"+messageNode[pl].id+"');");
}
}
The above has the feel of a truly horrible hack, and I feel sure I must have taken a wrong turn somewhere early on in my thought process. Can someone please tell me:
The correct way to go about putting nicely-formatted text inside a Dojo/Dijit Tree control.
The correct way to handle Dojo events, like where I can figure out what events are available for me to subscribe to.
A better JavaScript library to use (can I do what I want to with JQuery and avoid the all-around-the-houses approach seen above?).
PS: If you're naming a software project, give thought to its name's uniqueness in Google - I'm sure searching for "Dojo" documentation in Google would be easier without all the martial arts results getting in the way.
PPS: Firefox spellchecker knows how to spell "Atwood", correcting me when I put two 'T's instead of one. Is Jeff just that famous now?
I assume that you followed the dijit.Tree and dojo.data in Dojo 1.1 tutorial which directed you to pass the data to the tree control using a data store. That had me banging my head of a brick wall for a while.
Its not really a great approach and the alternative is not really well documented. You need to create a use model instead. I have included an example below of a tree model that I created for displaying the structure of an LDAP directory.
You will find the default implementation of the model in your dojo distribution at ./dijit/_tree/model.js. The comments should help you understand the functions supported by the model.
The IDirectoryService class the code below are stubs for server-side Java POJOs generated by Direct Web Remoting (DWR). I highly recommend DWR if you going to be doing a lot of client-server interaction.
dojo.declare("LDAPDirectoryTreeModel", [ dijit.tree.model ], {
getRoot : function(onItem) {
IDirectoryService.getRoots( function(roots) {
onItem(roots[0])
});
},
mayHaveChildren : function(item) {
return true;
},
getChildren : function(parentItem, onComplete) {
IDirectoryService.getChildrenImpl(parentItem, onComplete);
},
getIdentity : function(item) {
return item.dn;
},
getLabel : function(item) {
return item.rdn;
}
});
And here is an extract from the my JSP page where I created the model and used it to populate the tree control.
<div
dojoType="LDAPDirectoryTreeModel"
jsid="treeModel"
id="treeModel">
</div>
<div
jsid="tree"
id="tree"
dojoType="dijit.Tree" model="treeModel"
labelAttr="name"
label="${directory.host}:${directory.port}">
</div>