NativeScript Typings - mobile

I'm working through the NativeScript getting started tutorial in TypeScript:
http://developer.telerik.com/featured/getting-started-nativescript/
In one snippet of code, I see:
exports.loadSignUpView = function(args) {
page = args.object;
page.bindingContext = journeyInfo;
}
After some research I was able to type args as
import app = require("application");
exports.loadSignUpView = function(args: app.ApplicationEventData) {
//...
}
But that still does not help me type the page object above, which has the bindingContext property. What is the TypeScript type that corresponds to the page?

Page type is defined in the "ui/page" module and the type of the args of the loaded event is EventData (from the "data/observable" module).
So you can do something like this:
import observable = require("data/observable");
import pages = require("ui/page");
// Event handler for Page "loaded" event attached in main-page.xml
export function loadSignUpView (args: observable.EventData) {
// Get the event sender
var page = <pages.Page>args.object;
}
Few more useful tips to get you started:
NativeScript has TypeScript support build in since the 1.5 release. You can now use the NativeScript CLI to setup typescript project. You can check the documentation for more.
In the documentation there is more up to date getting-started guide
All of the code snippets in the docs have also a TypeScript version so that you can see the typings there - we love typescript ;)

Related

How to use service-worker background sync with typescript

I created a react project with TS (npx create-react-app my-app --template cra-template-pwa-typescript).
I followed the documentation : https://developers.google.com/web/updates/2015/12/background-sync). The following code is producing TS errors (even if it works):
// Register your service worker:
navigator.serviceWorker.register('/sw.js');
// Then later, request a one-off sync:
navigator.serviceWorker.ready.then(function(swRegistration) {
return swRegistration.sync.register('myFirstSync'); // error
});
self.addEventListener('sync', function(event) {
if (event.tag == 'syncSavedProjects') { // error
event.waitUntil(doSomeStuff()); // error
}
});
Property 'sync' does not exist on type 'ServiceWorkerRegistration'
Property 'tag' does not exist on type 'Event'
Property 'waitUntil' does not exist on type 'Event'
Looks like definitions are missing (lib.dom.d.ts)
There are a number of types that were removed from the standard type libraries in TypeScript v4.4.0, as described in this issue. Primarily, these are types related to web platform features that are not widely implemented (e.g. features that are Chrome-only at the moment). Background sync falls into that category.
The long-term plan is apparently, starting with TypeScript v4.5.0, to use standalone libraries like #types/web and #types/serviceworker, instead of the standard libraries that are updated with each TypeScript release. This means that in the future, upgrading your TypeScript dependency can be done independently from your type definition dependencies.
However, those libraries also have a policy of not including interfaces that are only available in a single browser. So I don't think that background sync is exposed in them either. There might be another #types/... library that does have them, but I have no been able to find them yet.
So, in terms of an actual solution today, the best approach I've found is to add a local copy of the old definitions to your TypeScript project. Here's a snippet of how we did this in the Workbox project for the background sync defintions:
interface SyncManager {
getTags(): Promise<string[]>;
register(tag: string): Promise<void>;
}
declare global {
interface ServiceWorkerRegistration {
readonly sync: SyncManager;
}
interface SyncEvent extends ExtendableEvent {
readonly lastChance: boolean;
readonly tag: string;
}
interface ServiceWorkerGlobalScopeEventMap {
sync: SyncEvent;
}
}

Storm-React-Diagram Demo custom link 1

Expected outcome:
I was trying to to achieve this feature using storm react diagram. (click this link to show demo)
The Desired outcome:
convert the TypeScript to JavaScript should work, but it keep having error.
Problem:
however I ran into an error when converting this typescript to JavaScript (see below code block)
import * as SRD from 'storm-react-diagrams';
// setup diagram engine
this.engine = new SRD.DiagramEngine();
this.engine.installDefaultFactories();
//
const pathfinding = this.engine.getLinkFactories().getFactory<SRD.PathFindingLinkFactory>SRD.PathFindingLinkFactory.NAME;
What I have tried,
const pathfinding = this.engine.getLinkFactories().getFactory(PathFindingLinkFactory.NAME);
but I got this error instead
Full disclosure, I have posted this on GitHub too.
Solved.
const pathfinding = this.engine.getLinkFactories()[PathFindingLinkFactory.NAME];

CommonJS require vs. ES6 import discrepancy

So, I am new to React. Apologies if I am missing something obvious, I'm wrestling with a weird issue with my ES6 imports.
I'm using the #typeform/embed module (0.12.1), which oddly links to a GitHub repo on npm but that repo doesn't exist. So I haven't been able to look into potentially related issues.
Anyways, whenever I do the following:
import typeformEmbed from '#typeform/embed'
My text editor shows that the type of typeformEmbed is a string, and when I go to invoke a function on it, it is always undefined. Gives me the 'ole cannot invoke property X on undefined TypeError. It almost looks as if it is trying to import the README?
But, then I opened up my Node REPL and could write:
const typeformEmbed = require('#typeform/embed')
and it works like a charm.
Is there some discrepancy between the two that I am missing?
Edit: I know that this question is pretty text-heavy, let me know if there is crucial information that I'm missing. I should mention that I built this project with create-react-app.
import * as typeformEmbed from '#typeform/embed';
const popUpHandler = () => {
typeformEmbed.makePopup(
'https://admin.typeform.com/to/PlBzgL',
{
mode: 'drawer_left',
autoOpen: true,
autoClose: 3,
hideScrollbars: true,
onSubmit: function () {
console.log('Typeform successfully submitted')
}
}
)}
Should work for you

AudioWorklet error: DOMException: The user aborted a request

I've successfully instantiated a simple AudioWorklet in React and wish to start a simple oscillator like in Google's example. In order to test run it, I am rendering a button whose onClick event calls the following:
src/App.jsx:
userGesture(){
//create a new AudioContext
this.context = new AudioContext();
//Add our Processor module to the AudioWorklet
this.context.audioWorklet.addModule('worklet/processor.js').then(() => {
//Create an oscillator and run it through the processor
let oscillator = new OscillatorNode(this.context);
let bypasser = new MyWorkletNode(this.context, 'my-worklet-processor');
//Connect to the context's destination and start
oscillator.connect(bypasser).connect(this.context.destination);
oscillator.start();
})
.catch((e => console.log(e)))
}
The problem is, on every click, addModule method is returning the following error:
DOMException: The user aborted a request.
I am running Chrome v66 on Ubuntu v16.0.4.
src/worklet/worklet-node.js:
export default class MyWorkletNode extends window.AudioWorkletNode {
constructor(context) {
super(context, 'my-worklet-processor');
}
}
src/worklet/processor.js
class MyWorkletProcessor extends AudioWorkletProcessor {
constructor() {
super();
}
process(inputs, outputs) {
let input = inputs[0];
let output = outputs[0];
for (let channel = 0; channel < output.length; ++channel) {
output[channel].set(input[channel]);
}
return true;
}
}
registerProcessor('my-worklet-processor', MyWorkletProcessor);
My code is straight JavaScript, not React, but I got the same error because the path provided to addModule was incorrect. In my case, both the script that calls addModule and the script provided as the argument to addModule reside in the same directory ("js"). In spite of that, I still had to include this directory in the path to eliminate the error:
...addModule('js/StreamTransmitter.js')...
I hope this helps. Good luck!
For anyone else getting this mysterious error, swallow your pride and check the following:
The processor doesn't have any errors.
The processor is calling external modules with proper path to the external file(s).
The external modules don't have any errors.
The promise will abort when external modules that are loaded via "import" have errors, or the paths to the modules can't be resolved (e.g. the path's to the modules are wrong and don't point to existing files).
This worked for me: serve your worklet files from public folder instead of src. The addModule(url) function points there by default, so addModule('worklets/foo.js') references file public\worklets\foo.js
Source: https://hackernoon.com/implementing-audioworklets-with-react-8a80a470474
This seems to be a bug in the Chromium module loader, it parses the worklet/processor.js file by removing whitespace, which in turn causes it to have JavaScript syntax errors everywhere, which then finally causes this generic non-explanatory error message to show up.
The solution is to serve your worklet-processors (e.g. worklet/processor.js in your case) with:
Content-Type: application/javascript
or
Content-Type: text/javascript
I also experienced this error but due to a Webpack issue.
Turns out webpack doesn't support worklets like it supports web workers (see this issue).
I would recommend using worker-url with webpack.
Install worker-url
npm i --save-dev worker-url
Update your webpack config to include the WorkerUrl plugin.
const WorkerUrlPlugin = require('worker-url/plugin');
module.exports = {
// ...
plugins: [new WorkerUrlPlugin()],
// ...
};
Use WorkerUrl like so:
import { WorkerUrl } from 'worker-url';
const workletUrl = new WorkerUrl(
new URL('./random-noise-processor', import.meta.url),
{ name: 'worklet' },
);
await context.audioWorklet.addModule(workletUrl);
The Error "DOMException: The user aborted a request." happens when the AudioWorklet.addModule() function cannot load the file from the path or URL you provided. Refer to this MDN page
The api AudioWorklet.addModule() expects a String containing the URL of a JavaScript file with the module to add.
It can be an internal URL that points to your public folder where the browser loads your static files in this case -> 'worklet/processor.js if the worklet folder is inside the public directory of your React app.
You can modify your code as below.
this.context.audioWorklet.addModule('worklet/processor.js')
In this case the audioWorklet.addModule() method expects the path to point to your public folder. It can also be an external URL for example a link to Github repository that loads the JS file.
Changing:
this.context.audioWorklet.addModule('worklet/processor.js')
with
this.context.audioWorklet.addModule('../worklet/processor.js')
worked for me.

Setting up PDF.js to work with Meteor + Reactjs project (want to use text layer)

I've been working on a project using Meteor and React, which needs a PDF viewer with the ability to select text.
I'm currently trying to achieve this with Mozilla's PDF.js, but am having some trouble getting started. I'm a long time reader, first time asker at stackoverflow.
I've installed PDF.js with npm.
npm install pdfjs-dist --save
Now I'm trying to modify the example from pdf.js's github project here to create a React component that will render a PDF from a supplied file path and include a text layer.
imports/ui/components/PDF/PDFText.jsx
import React from 'react';
require ('pdfjs-dist/build/pdf.combined');
require ('pdfjs-dist/web/compatibility');
export default class PDFText extends React.Component {
renderPDF() {
PDFJS.workerSrc = '/node_modules/pdfjs-dist/build/pdf.worker.js';
const container = document.getElementById('pdf-container');
const scale = 1;
const pageNumber = 1;
PDFJS.getDocument(this.props.file).then(function(pdf) {
return pdf.getPage(pageNumber).then(function(page) {
var pdfPageView = new PDFJS.PDFPageView({
container: container,
id: pageNumber,
scale: scale,
defaultViewport: page.getViewport(scale),
textLayerFactory: new PDFJS.DefaultTextLayerFactory()
});
pdfPageView.setPdfPage(page);
return pdfPageView.draw();
});
});
}
render() {
this.renderPDF()
return (
<div id='pdf-container'></div>
);
}
}
If I include this component in page I get the following error:
Uncaught (in promise) TypeError: PDFJS.DefaultTextLayerFactory is not a constructor
The next thing I tried was including 'pdfjs-dist/web/pdf_viewer' in my code, as this is where DefaultTextLayerFactory is declared. I modified the code above to add the following line above the class declaration:
require ('pdfjs-dist/web/pdf_viewer');
When I run the code now, I get a different error.
Uncaught TypeError: Cannot read property 'PDFJS' of undefined
at Object.<anonymous> (modules.js?hash=9dd20a3…:114918)
at __w_pdfjs_require__ (modules.js?hash=9dd20a3…:114838)
at Object.<anonymous> (modules.js?hash=9dd20a3…:117449)
at __w_pdfjs_require__ (modules.js?hash=9dd20a3…:114838)
at Object.<anonymous> (modules.js?hash=9dd20a3…:118157)
at __w_pdfjs_require__ (modules.js?hash=9dd20a3…:114838)
at module.exports (modules.js?hash=9dd20a3…:114884)
at modules.js?hash=9dd20a3…:114887
at webpackUniversalModuleDefinition (modules.js?hash=9dd20a3…:114811)
at pdf_viewer.js (modules.js?hash=9dd20a3…:114818)
I'm really unsure what is going on here. I noticed that the function complaining refers to webpack - which I haven't been using.
I've also tried including the following check at the start of my code (this is taken from pageviewer.js in the github link above).
if (!PDFJS.PDFViewer || !PDFJS.getDocument) {
alert('Please build the pdfjs-dist library using\n' +
' `gulp dist`');
}
My code does in fact trigger that alert (PDFJS.PDFViewer is undefined) but the message doesn't seem correct as I installed the built pdfjs-dist library using npm. That message seems for people who cloned the repo. There isn't a gulp file in the pdfjs-dist directory - which makes sense.
I'm sure part of thep problem is that I'm experimenting with a lot of new tools here. This is my first time working with meteor, react, node, and pdf.js, so apologies in advance if I've made an obvious rookie mistake.
For the record I've tried a few other libraries, including:
mikecousins/react-pdf-js (worked reasonably well for simply displaying a pdf with no text layer).
peerlibrary/meteor-pdf.js (I hit some errors with this one as well, and I didn't pursue it too much further as the repo hasn't been touched in a couple of years).
Hopefully that's enough information for someone to spot the issue. My theory is that there's some other set up step I need to do to get this working for meteor or react (and that's why it hasn't been obvious from the "getting started" in the PDF.js website.
Also, I'm not locked in to PDF.js, so if the easiest solution to my problem is to use something else, I'd be happy to try that.
Thanks for your time

Resources