Cannot read property on of undefined. Electron BrowserWindow object - ecmascript-6

I am trying to learn Electron, but am running into an issue with the Pluralsight tutorial I am using. I installed the 'electron-prebuilt' module. I get an error everytime I run "npm start". The window opens as expected, but the error message that pops up in a dialog box kind of ruins the whole thing. Here is the error:
Uncaught Exception:
TypeError: Cannot read property 'on' of undefined at Object.
There's more to the long error message but it won't let me copy and paste, and the rest of the error just refers to the location of the supposed problem on line 14 of my main.js code. Here is my main.js file:
const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow
let mainWindow
app.on('ready', _ => {
mainWindow = new BrowserWindow({
height: 400,
width: 400
})
})
mainWindow.on('closed', _ => {
console.log('closed')
mainWindow = null
})
It's indicating that the BrowserWindow object I created doesn't have an "on" method, but I know this to be false per the Electron documentation:
https://electronjs.org/docs/api/browser-window
So I'm thinking that the value of mainWindow just isn't being set. I could try instantiating mainWindow with a new BrowserWindow object at the time I declare it, but I get an error message if I try that indicating that I can only instantiate BrowserWindow objects in ready functions.

you have to understand how callbacks work in node.js, callbacks are executed asynchronously, before app.onready fires, mainWindow is still undefined hence the declaration of let mainWindow assigns undefined to mainWindow, take mainWindow.on("closed", ....) into the app.on("ready") event handler. Do this
const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow
let mainWindow
app.on('ready', _ => {
mainWindow = new BrowserWindow({
height: 400,
width: 400
})
mainWindow.on('closed', _ => {
console.log('closed')
mainWindow = null
})
})

This error also occurs if you are just calling node on your electron script instead of electron. Your npm start script should be calling npx electron . instead, so try running npx electron . or npx electron main.js first. See this relevant issue here:
https://github.com/electron/electron/issues/7475

Related

Why I get chrome launch error, when I export some data with html-to-xslx package in node js

When I try to export data with html-to-xslx npm package, this message displayed:
Error: Failed to launch chrome!
[0221/145806.785119:ERROR:zygote_host_impl_linux.cc(89)] Running as
root without --no-sandbox is not supported. See
https://crbug.com/638180.TROUBLESHOOTING:
https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md
If we want to lunch chrome with root privilege, we must add --node-sandbox in 'chrome-page-eval' constructor: launchOptions: {headless: true, args:['--no-sandbox']}
Here is a full example:
const conversionFactory = require('html-to-xlsx');
const chromeEval = require('chrome-page-eval')({ puppeteer, launchOptions: {headless: true, args:['--no-sandbox']} });
const conversion = conversionFactory({
extract: chromeEval
})
This way worked for me

Cannot read property 'environment' of null - ionic native google maps

When running my ionic project with ionic serve -c
Everytime, I get an this error :
ERROR TypeError: Cannot read property 'environment' of null
at Function.Environment.setEnv (index.js:1980)
at HomePage.webpackJsonp.194.HomePage.loadMap (home.ts:98)
at HomePage.webpackJsonp.194.HomePage.ionViewDidLoad (home.ts:45)
at ViewController._lifecycle (view-controller.js:486)
at ViewController._didLoad (view-controller.js:369)
at NavControllerBase._didLoad (nav-controller-base.js:768)
at t.invoke (polyfills.js:3)
at Object.onInvoke (core.js:4760)
at t.invoke (polyfills.js:3)
at r.run (polyfills.js:3)
There is the loadMap method :
loadMap() {
Environment.setEnv({
'API_KEY_FOR_BROWSER_DEBUG' : '',
'API_KEY_FOR_BROWSER_RELEASE' : ''
})
this.geoLocation.getCurrentPosition().then((resp) => {
this.latitude = resp.coords.latitude;
this.longitude = resp.coords.longitude;
console.log(this.latitude);
console.log(this.longitude);
let CurrentPosition : LatLng = new LatLng(this.latitude,this.longitude);
let CameraPosition : CameraPosition<ILatLng> = {
target : CurrentPosition,
zoom : 18
};
this.addMarker();
this.map.moveCamera(CameraPosition);
}).catch((error) => {
console.log('Error getting location', error);
});
this.map = GoogleMaps.create('map_canvas');
}
I don't understand. I only launch my component after the device.isReady() is fired, so it should not be a lifecycle problem.
Do you have any idea as to where does this come from?
Thank you!
EDIT : When using the ionic cordova run browser -l command, the map is loaded without error the first time then on some refresh of the webpage, the error appears again, without me changing anything to the code...
I had the same problem I found the solution on this thread https://stackoverflow.com/a/52681481/6560704
You need to build your platforms to create that 'environment' variable, by using CLI for example :
ionic cordova build browser -l
Hope this will help
Problem solved !
It was in fact a lifecycle problem. I was attributing the HomePage to the rootPage in app.components.ts before the device was ready.

Geolocator.RequestAccessAsync throws "method called at unexpected time" exception

I have a chunk of code I use to get device location. This is done in a monogame windows uwp project. The following code worked before (I was on VS2015 Community). I recent did a fresh OS and install VS2017 Community. I finally got my project to build and run. The only thing not working is the Geolocator.RequestAccessAsync is throwing a "method called at unexpected time" exception. Any ideas?
public async Task<Vector2> GetDeviceGps()
{
var accessStatus = await Geolocator.RequestAccessAsync();
switch (accessStatus)
{
case GeolocationAccessStatus.Allowed:
// If DesiredAccuracy or DesiredAccuracyInMeters are not set (or value is 0), DesiredAccuracy.Default is used.
Geolocator geolocator = new Geolocator { DesiredAccuracyInMeters = 10 };
// Subscribe to the StatusChanged event to get updates of location status changes.
//geolocator.StatusChanged += OnStatusChanged;
// Carry out the operation.
Geoposition pos = await geolocator.GetGeopositionAsync();
return new Vector2((float)pos.Coordinate.Point.Position.Longitude, (float)pos.Coordinate.Point.Position.Latitude);
case GeolocationAccessStatus.Denied:
//Do something!
break;
case GeolocationAccessStatus.Unspecified:
//Murp
break;
}
return Vector2.Zero;
}
This is invoked and handled like so (called from update method of game):
mapper.GetDeviceGps().ContinueWith(pos =>
{
Vector2 bob = pos.Result;
});
When you run the RequestAccessAsync for the first time in your app, the user will be asked to grant your app the location permission. Therefore the method needs to be executed in the UI thread.

How to capture $compile or $digest error? (AngularJS directive with templateUrl)

I'm writing a unit test of an AngularJS 1.x directive.
If I use "template" it works.
If I use "templateUrl" it does not work (the directive element remains the same original HTML instead of being "compiled").
This is how I create the directive element to test in Jasmine:
function createDirectiveElement() {
scope = $rootScope.$new();
var elementHtml = '<my-directive>my directive</my-directive>';
var element = $compile(elementHtml)(scope);
scope.$digest();
if (element[0].tagName == "my-directive".toUpperCase()) throw Error("Directive is not compiled");
return element;
};
(this does not actually work, see Update for real code)
I'm using this workaround to use the $httpBackend from ngMockE2E (instead of the one in ngMock). In the browser developer "network" tab I don't see any request to the template file. It seems to work because I solved the error "Object # has no method 'passThrough'".
I know that the call to the template is done asynchronously using the $httpBackend (this means $compile exit before the template is really applied).
My question is:
obviously $compile is not doing what I expect. How can I trap this error?
If I use a wrong address in the templateUrl I don't receive any error.
How can I found the problem happened when I called $compile(directive) or scope.$digest() ?
Thanks,
Alex
[Solution]
As suggested by #Corvusoft I inject $exceptionHandler and I check for errors after every test.
In the end this is the only code I have added:
afterEach(inject(function ($exceptionHandler) {
if ($exceptionHandler.errors.length > 0)
throw $exceptionHandler.errors;
}));
Now I can clearly see the errors occurred in the Jasmine test result (instead of search for them in the console), example:
Error: Unexpected request: GET /api/category/list
No more request expected,Error: Unexpected request: GET /api/category/list
No more request expected thrown
And, most important, my tests does not pass in case there are some errors.
[Update to show real example case]
Actually the real code to make templateUrl work use asynchronous beforeEach ("done") and a timeout to wait the end of compile/digest.
My directive use some prividers/services and the template contains other directives which in turn use their templateUrl and make calls to some APIs in the link function().
This is the current (working) test code:
// workaround to have .passThrough() in $httpBackend
beforeEach(angular.mock.http.init); // set $httpBackend to use the ngMockE2E to have the .passThrough()
afterEach(angular.mock.http.reset); // restore the $httpBackend to use ngMock
beforeEach(inject(function (_$compile_, _$rootScope_, _$http_, $httpBackend, $templateCache, $injector) {
$compile = _$compile_;
$rootScope = _$rootScope_;
$http = _$http_;
$httpBackend.whenGET(/\/Scripts of my app\/Angular\/*/).passThrough();
$httpBackend.whenGET(/\/api\/*/).passThrough(); // comment out this to see the errors in Jasmine
}));
afterEach(inject(function ($exceptionHandler) {
if ($exceptionHandler.errors.length > 0)
throw $exceptionHandler.errors;
}));
beforeEach(function(done) {
createDirectiveElementAsync(function (_element_) {
element = _element_;
scope = element.isolateScope();
done();
});
});
function createDirectiveElementAsync(callback) {
var scope = $rootScope.$new();
var elementHtml = '<my-directive>directive</my-directive>';
var element = $compile(elementHtml)(scope);
scope.$digest();
// I haven't found an "event" to know when the compile/digest end
setTimeout(function () {
if (element.tagName == "my-directive".toUpperCase()) throw Error("Directive is not compiled");
callback(element);
}, 0.05*1000); // HACK: change it accordingly to your system/code
};
it("is compiled", function () {
expect(element).toBeDefined();
expect(element.tagName).not.toEqual("my-directive".toUpperCase());
});
I hope this example helps someone else.
$exceptionHandler
Any uncaught exception in AngularJS expressions is delegated to this
service. The default implementation simply delegates to $log.error
which logs it into the browser console.
In unit tests, if angular-mocks.js is loaded, this service is overridden by mock $exceptionHandler which aids in testing.
angular.
module('exceptionOverwrite', []).
factory('$exceptionHandler', ['$log', 'logErrorsToBackend', function($log, logErrorsToBackend) {
return function myExceptionHandler(exception, cause) {
logErrorsToBackend(exception, cause);
$log.warn(exception, cause);
};
}]);

Polymer key global variables undefined. Why?

I've got a strange set of errors as I load up my application
polymer-micro.html:117 Uncaught TypeError: Cannot read property '_makeReady' of undefined
(anonymous function) # polymer-micro.html:117
The indefined in this first one is Polymer.RenderStatus
polymer.html:3417 Uncaught TypeError: Polymer.dom is not a function
_findStyleHost # polymer.html:3417
_computeStyleProperties # polymer.html:3461
_applyCustomProperties # polymer.html:3652
fn # polymer.html:3638
Obviously Polymer.dom ought to be a function. why is it not?
Uncaught TypeError: Cannot read property '_isEventBogus' of undefined
_notifyListener # polymer.html:2012
(anonymous function) # polymer.html:1534
fire # polymer.html:1277
_notifyChange # polymer.html:1372
_notifyEffect # polymer.html:1553
_effectEffects # polymer.html:1405
_propertySetter # polymer.html:1389
setter # polymer.html:1468q
ueryHandler # iron-media-query.html:116
This is a media query that generates this error everytime we move the width of the screen across the media query boundary. The undefined variable in this case is Polymer.Bind
If I put a breakpoint at the top of polymer.html (just after the script tag) The errors go away when I then let it go. This almost implies that normally it is running without letting polymer-mini.html load.
I am running with chrome, and the tests in index.html as to whether to load the webcomponents-lite.js polyfill means it doesn't load.
I am stuck about what to do about debugging this issue. Any ideas?
It turns out that the positioning of the initialisation script in index.html is the cause of these problems. I had copied the Polymer Shop app which places the script at the bottom of the body. The app created by the polymer-cli tool (with the app-drawer template) places the script in the header, before importing the my-app element.
I suspect the reason the shop app doesn't have problems is the header is not doing any animation. I am using a blend-background effect in my header and that might be why it fails.
Anyway, moving the script which includes the Polymer initialization into the header solved the problem.
Adding async to the import solved it for me.
<link rel="import" href="/src/your-app.html" async>
Instead of
<link rel="import" href="/src/your-app.html">
I'm experimenting with the 2.0 preview and had a similar set of errors trying to follow Rob Dodson's routing Polycast (#47, 48 ish). This is what worked after many hours of trying other solutions:
**<script src="/bower_components/webcomponentsjs/webcomponents-lite.js">**
// Setup Polymer options
window.Polymer = {
dom: 'shadow',
lazyRegister: true
};
// Load webcomponentsjs polyfill if browser does not support native Web Components
(function() {
'use strict';
var onload = function() {
// For native Imports, manually fire WebComponentsReady so user code
// can use the same code path for native and polyfill'd imports.
if (!window.HTMLImports) {
document.dispatchEvent(
new CustomEvent('WebComponentsReady', {bubbles: true})
);
}
};
var webComponentsSupported = (
'registerElement' in document
&& 'import' in document.createElement('link')
&& 'content' in document.createElement('template')
);
if (!webComponentsSupported) {
**// var script = document.createElement('script');
// script.async = true;
// script.src = '/bower_components/webcomponentsjs/webcomponents-lite.min.js';
// script.onload = onload;
// document.head.appendChild(script);**
} else {
onload();
}
})();
// Load pre-caching Service Worker
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/service-worker.js');
});
}
</script>