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
Related
I am using protractor. I understand that protractor has Jquery like syntax but I need something that can
create conditions, variables and loops based on DOM elements in some of my testing. I want to be able to use querySelector. Using just promises won't let me do the kind of testing I need to do.
When I run it, it says:
Failed: Cannot read property 'querySelector' of undefined
or
Failed: document is not defined
or
Failed: window is not defined
I've set up a test to test this issue. It runs off a random web page that I was looking at it. It selects the footer using protractor and then attempts it using querySelector. If I enter the querySelector portion in the console, it runs the code correctly. I've also tried variations of querySelector, using window.document; this also works in the browser but not in protractor.
describe("Test", function()
{
it('This is a test to test protractor' , function()
{
browser.waitForAngularEnabled(false);
browser.get("https://facebook.github.io/jest/");
$("#footer").getAttribute("innerHTML").then( function(value)
{
console.log("inside value then");
console.log(value);
});
var queryse = document.querySelector("#footer").innerHTML;
// var queryse = browser.document.querySelector("#footer").innerHTML;
// var queryse = window.document.querySelector("#footer").innerHTML;
console.log('query selector');
console.log(queryse);
});
});
The code you're running in Protractor test case doesn't really run in browser, in fact it's executed in Node.js. You should think of it as an API that will afterwards communicate with the browser through WebDriver. That means that you cannot use browser specific JavaScript API in the code. The $ helper is just there to make the syntax easy and understandable without knowing anything about Selenium. That's why document and window are inaccessible for you. If you want to read more about that: https://github.com/angular/protractor/blob/master/docs/locators.md
#Nhor's answer is mostly correct in terms of the environments and why you cannot use document and window directly. However, for what it's worth, you can definitely find elements in the DOM through executeScript. The only question is, why do you need to do this?
Any locator you can use in the DOM, you can use in Protractor (though the syntax might be different). Here's an example, I used innerHTML because that's what you were trying in your case:
describe('Protractor Demo App', function() {
it('element test', function() {
browser.get('http://juliemr.github.io/protractor-demo/');
var el = browser.executeScript('return document.querySelector("h3").innerHTML');
el.then(function (text) {
console.log(text); // logs "Super Calculator"
});
});
});
Finally, it's important to note that this el is restricted to javascript functions from within that executeScript call. It is not a version of Protractor's ElementFinder, you cannot perform actions like getText() on it (though it is still a Promise, so you need to call .then()). You can do a console log on the el to see what's in that object.
This probably has been answered before but I have tried for 48 hours now to find an answer with now luck. Posting this is a last resort.
So I have this Tetris clone and it works as seen here: http://www.crawfordcomputing.com/portfolio/Jetris.php
But it does not work in this single page angular app:
http://www.crawfordcomputing.com/AkadineWebOS/
I am re-coding the whole site to be a AngularJS single page app. To this end, I load the html via ng-bind-html and the compile directive found here: AngularJS directive in ng-bind-html.
The html string I am binding is exactly: EDIT: tried making canvas a childnode, did not work.<div><canvas id='gamewindow' width='780px' height='560px'></canvas></div>
The necessary scripts are loaded via the function found here: Single page application - load js file dynamically based on partial view
Note: html5jetris.js is actually an object: var jetris = { startgame: function(), ...};
Using firebug, I can see all added elements and the scripts in the DOM. I also am assuming that being a single page already loaded that I cannot use window.onload = jetris.startGame; after the closing ";" of var jetris = {};
1) I tried putting an alert("hello"); as second to last line (just before the call to startGame) and tried stepping through with firebug. It appears that html5jetris.js, while loaded, is not running.
2) I tried to access the canvas by id directly from address bar with javascript:getElementByID("gamewindow").innerHTML = "hello";
no success; this was several seconds after the ng-bind-html executed well past the 1-1.5 seconds it takes angular to load it.
3) if I pre-emptivly load all the js in my index.php, then firefox will step through it. But I only want to load the javascript when needed. This does not fix not being able to access the canvas by id.
4) by it self, Jetris works, just not loaded dynamically by AngularJS.
Note: Jetris does not require jQuery, even though it's there for Angular. It depends on my own utitlty.js (made as part of a javascript class, converted to object: var U = {};) and my own html5canvas.js (again, var canvas = {};) Since these are objects, the variables in them should not bump heads with anything jQuery or Angular.
Any ideas?
here is the directive:
.directive('compile', ['$compile', function ($compile) {
return function(scope, element, attrs) { //taken from Joël (Thank you!) source: https://stackoverflow.com/questions/26594153/angularjs-directive-in-ng-bind-html
scope.$watch(
function(scope) {
// watch the 'compile' expression for changes
return scope.$eval(attrs.compile);
},
function(value) {
// when the 'compile' expression changes
// assign it into the current DOM
element.html(value);
// compile the new DOM and link it to the current
// scope.
// NOTE: we only compile .childNodes so that
// we don't get into infinite loop compiling ourselves
$compile(element.contents())(scope);
}
);
};
}])
Jetris.php:
<?php //Jon Crawford AkadineWebOS pages/jetris.php
//describe window
$window = array();
$window['content'] = "<canvas id='gamewindow' width='780px' height='560px'></canvas>";
$window['title'] = "Jetris";
$window['x'] = 20;
$window['y'] = 250;
$window['id'] = 900;
$window['requireJS'] = array();
$window['requireJS'][0] = "scripts/html5Jetris.js";
$window['requireJS'][1] = "scripts/html5Canvas.js";
$window['requireJS'][2] = "scripts/utilities.js";
echo json_encode($window);
?>
This gets loaded to a div with title bar and exit button that is draggable. My menu system is icon like. My AkadineWebOS looks like a regular desktop. I have an about.php and a welcome.php that work just fine in my div-windows.
Ok so this is a special case I probably did not clarify my question. Here are the steps I used to accomplish my goal.
To load an HTML formated string to the DOM I used a $compile directive by Joël (Thank you!) source: AngularJS directive in ng-bind-html
To load external dependency script files, I used a load script function by Ben Thielker (Thank you!) source: Single page application - load js file dynamically based on partial view
Then I change the onload in my java game Jetris to: var externalJS = { run: function() { window.jetris.startGame(); } };
So that I will not have to re-code my angular app whenever I want to add a new game or other javascript app, this allows my app to check if var externalJS is undefined and if is is defined, it executes externalJS.run();. If the app's div-window is closed, this will effectively restart it when reopened.
Now since everything is loaded using Angular's HTTP module, you have to wait for Angulars promise to finish for everything to be loaded. If I try to run it to soon, I get a blank window and no game. To that end, I use
setTimeout(function() {
if (typeof externalJS != 'undefined'){
externalJS.run();
}},750);
in the HTTP module's successCallback to give it some time.
Here is a link to a working Alpha of the project, with all issues questioned here ironed out. You can drag the windows and icons, open more than one of the same window like a normal desktop unless a oneInstance flag is set like with Jetris, and you can play Jetris! Check it out! AkadineWebOS
Triva: I created the acronym Akadine as a online handle with a program that made random readable words (not real, just readable) years ago, and came up only recently with Advanced Kiosk And Dynamic Internet Navigation Environment.
im creating a platform to user automated tests to verify if a widget is functional. I already made the tutorials and the saw the examples but still i can figure out what's happening.
the widget that im trying to test is made with iframes without src attribute and with im trying to find a element inside of that iframe without src attribute.`define(function (require) {
var registerSuite = require('intern!object');
var assert = require('intern/chai!assert');
registerSuite({
name: 'index',
'greeting form': function () {
return this.remote
.get(require.toUrl('localhost:3000'))
.findById('iframeId')
.switchToFrame('iframeId')
.findById('buttonID');
}
});
});`
With this code it happens that the intern runner returns a error saying that it wasn't unable to find the element. But when i try to run the same code on a iframe with a "src" attribute it finds the correct element and doesn't returns any error.
anyone could help ??
In the above code, you should clear the search context before trying to find an element in the iframe, like:
return this.remote
.get(require.toUrl('localhost:3000'))
.findById('iframeId')
.end()
.switchToFrame('iframeId')
.findById('buttonID')
This is assuming the findById call is to wait for the iframe to be added to the page. If you don't need to do that, just leave out the findById('iframeId') call and you should be good.
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);
I'm struggling with this even after reading the MSDN documentation and the following online guides:
Codefoster
Stephen Walter
I think my problem is easy to fix and that I just am thinking about something in the wrong way. Basically I am querying my web service and on success running the following method. I am then trying to bind the result to my listview. For now I am using a hardcoded value publicMembers.itemlistwhich has been declared at the top of the document just to make sure I can actually bind to the list before doing it with my query results. Ignore line 2 for now.
Success Method:
_lookUpSuccess: function xhrSucceed(Result) {
var response = JSON.parse(Result.responseText);
listView = document.querySelector("#termTest");
ui.setOptions(listView, {
itemDataSource: publicMembers.itemList,
itemTemplate: document.querySelector(".itemtemplate"),
})
},
Now, instead of using document.querySelector, I have also tried with WinJS.Utilities.id and WinJS.Utilities.query, neither of which worked either. This doesn't break my code and introduce an error but it doesn't bind to the listview either so I think I have an issue in querying the right DOM element. However exactly the same code does work if I add it to the top of the script, it is only when I place it in this method that it stops working.
EDIT: Also to clarify, when I debug publicMembers.itemList is storing the values I expect them to be.
Please point out if I have explained things poorly and I will try and improve my question.
Thanks.
I haven't used WinJS.UI.setOptions, but rather this other way of setting the data source. Can you see if it works?
_lookUpSuccess: function xhrSucceed(result) {
var response = JSON.parse(result.responseText);
listView = document.querySelector("#termTest");
listView.winControl.itemDataSource = publicMembers.itemList;
},
This would assume you're defining the itemTemplate as part of the data-win-options attribute of your ListView's HTML element. You could also probably just do listView.winControl.itemTemplate = document.querySelector(".itemtemplate") if you prefer to set it programmatically.