I am working with the FormData object, while my code works well on Chrome, Microsoft Edge spits out the following error message Object doesn't support property or method 'entries' – which corresponds to the following code:
for(let pair of formData.entries()) {
...
}
I've tried replacing .entries() with .getAll(), however Microsoft Edge doesn't recognize either of both methods.
Is there a way to get this functionality (iterating over FormData files) out of Microsoft Edge?
FormData Microsoft Edge Console Dump
2/10/2020 UPDATE:
Like #Monomachus said, first try adding this line to polyfill.ts:
import 'core-js/es7/object';
If this fixes it, make sure to give his answer credit! If needed, you can manually define it using the instructions below:
Original Response:
Essentially, a polyfill is a way you can manually define a function that isn't natively supported on a specific platform/browser.
In your case, there is a basic definition of the function Object.entries given here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries#Polyfill
They provide this simple, ready to deploy definition:
if (!Object.entries)
Object.entries = function( obj ){
var ownProps = Object.keys( obj ),
i = ownProps.length,
resArray = new Array(i); // preallocate the Array
while (i--)
resArray[i] = [ownProps[i], obj[ownProps[i]]];
return resArray;
};
Looking at the code above, the first thing it checks is if Object.entries exists. If it does, no worries, but if it doesn't exist, then it creates it...
As long as this function gets defined before you actually call it in your code, you should be fine.
Using something like angular-cli, they provide a polyfills.ts file (which gets executed before your app is run) where you can place code like this or import files containing definitions you'll need.
10/30/2018 UPDATE:
#apsillers correctly pointed out the answer above does not apply to FormData.entries(), but to Object.entries() instead.
Solution for FormData.entries() (this worked for me):
https://stackoverflow.com/a/49556416/3806701
Basically, import this poly-fill:
<script src="https://unpkg.com/formdata-polyfill"></script>
Then you can iterate FormData as follows:
var formDataEntries = (<any>formData).entries(), formDataEntry = formDataEntries.next(), pair;
while (!formDataEntry.done) {
pair = formDataEntry.value;
console.log(pair[0] + ', ' + pair[1]);
formDataEntry = formDataEntries.next();
}
If you're in an Angular App please add this line to your polyfills.ts file
import 'core-js/es7/object';
It will import all the new methods on Object, including entries
By importing
import 'core-js/es7/object';
if you are getting error
Module not found: Error: Can't resolve 'core-js/es7/object'
then Change all "es6" and "es7" to "es" in your imports.
import 'core-js/es/object';
I have added the below code in my polyfills.ts and it worked for me.
import 'core-js/es7/object';
import 'core-js/es7/array';
if (!Object.entries)
{ Object.entries = function(obj)
{
var ownProps = Object.keys(obj),
i = ownProps.length,
resArray = new Array(i); // preallocate the Array while (i--)
resArray[i] = [ownProps[i], obj[ownProps[i]]];
return resArray;
};
}
Related
I have a pretty straightforward piece of Typescript code that parses a specific data format, the input is a UInt8Array. I've optimized it as far as I can, but I think this rather simple parser should be able to run faster than I can make it run as JS. I wanted to try out writing it in web assembly using AssemblyScript to make sure I'm not running into any quirks of the Javascript engines.
As I figured out now, I can't just pass a TypedArray to Wasm and have it work automatically. As far as I understand, I can pass a pointer to the array and should be able to access this directly from Wasm without copying the array. But I can't get this to work with AssemblyScript.
The following is a minimal example that shows how I'm failing to pass an ArrayBuffer to Wasm.
The code to set up the Wasm export is mostly from the automatically generated boilerplate:
const fs = require("fs");
const compiled = new WebAssembly.Module(
fs.readFileSync(__dirname + "/build/optimized.wasm")
);
const imports = {
env: {
abort(msgPtr, filePtr, line, column) {
throw new Error(`index.ts: abort at [${line}:${column}]`);
}
}
};
Object.defineProperty(module, "exports", {
get: () => new WebAssembly.Instance(compiled, imports).exports
});
The following code invokes the WASM, index.js is the glue code above.
const m = require("./index.js");
const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
const result = m.parse(data.buffer);
And the AssemblyScript that is compiled to WASM is the following:
import "allocator/arena";
export function parse(offset: usize): number {
return load<u8>(offset);
}
I get a "RuntimeError: memory access out of bounds" when I execute that code.
The major problem is that the errors I get back from Wasm are simply not helpful to figure this out on my own. I'm obviously missing some major aspects of how this actually works behind the scenes.
How do I actually pass a TypedArray or an ArrayBuffer from JS to Wasm using AssemblyScript?
In AssemblyScript, there are many ways to read data from the memory. The quickest and fastest way to get this data is to use a linked function in your module's function imports to return a pointer to the data itself.
let myData = new Float64Array(100); // have some data in AssemblyScript
// We should specify the location of our linked function
#external("env", "sendFloat64Array")
declare function sendFloat64Array(pointer: usize, length: i32): void;
/**
* The underlying array buffer has a special property called `data` which
* points to the start of the memory.
*/
sendFloat64Data(myData.buffer.data, myData.length);
Then in JavaScript, we can use the Float64Array constructor inside our linked function to return the values directly.
/**
* This is the fastest way to receive the data. Add a linked function like this.
*/
imports.env.sendFloat64Array = function sendFloat64Array(pointer, length) {
var data = new Float64Array(wasmmodule.memory.buffer, pointer, length);
};
However, there is a much clearer way to obtain the data, and it involves returning a reference from AssemblyScript, and then using the AssemblyScript loader.
let myData = new Float64Array(100); // have some data in AssemblyScript
export function getData(): Float64Array {
return myData;
}
Then in JavaScript, we can use the ASUtil loader provided by AssemblyScript.
import { instantiateStreaming } from "assemblyscript/lib/loader";
let wasm: ASUtil = await instantiateStreaming(fetch("myAssemblyScriptModule.wasm"), imports);
let dataReference: number = wasm.getData();
let data: Float64Array = wasm.getArray(Float64Array, dataReference);
I highly recommend using the second example for code clarity reasons, unless performance is absolutely critical.
Good luck with your AssemblyScript project!
Edit: Here is a minimal project that illustrates my issue. You can see the error described by serving it to the browser: pub get and then either pub serve (dartium) or pub build --mode=debug (other browsers).
How can I access an arbitrary JavaScript property from Dart through a JsObjectImpl? I am using the ace.js library with an interop to Dart that I've adapted from a typescript interface, and the method I am calling returns a plain javascript object with key-value pairs.
Dart gives me a JsObjectImpl, which cannot be casted to a Map or a JsObject, both of which have [] accessors. It confusingly seems to inherit from the deprecated JSObject (note the 's' is capitalized in the latter) which does not have the [] accessor, so I can't get the data out.
Some error messages:
When attempting a cast from JsObjectImpl to JsObject:
ORIGINAL EXCEPTION: type 'JSObjectImpl' is not a subtype of type 'JsObject' of 'obj' where
JSObjectImpl is from dart:js
JsObject is from dart:js. I get a similar message when using Map as well.
Looking at the object in the debugger, I can frustratingly see the property in JS view but not in the Dart object: The 4: Object is the data I want.
Ok, this was a fun one, happy holidays :)
It looks like Map is not a supported auto-conversion for package:js. So a couple of things:
Filed https://github.com/dart-lang/sdk/issues/28194
Sent your a PR introducing a workaround
For interested parties, we can use the browser-native Object.keys:
#JS()
library example;
import 'package:js/js.dart';
/// A workaround to converting an object from JS to a Dart Map.
Map jsToMap(jsObject) {
return new Map.fromIterable(
_getKeysOfObject(jsObject),
value: (key) => getProperty(jsObject, key),
);
}
// Both of these interfaces exist to call `Object.keys` from Dart.
//
// But you don't use them directly. Just see `jsToMap`.
#JS('Object.keys')
external List<String> _getKeysOfObject(jsObject);
And call it once we have an arbitrary JavaScript object:
var properties = jsToMap(toy.getData());
print(properties);
I had to modify #matanlurey solution so it works on dart 2.12 and is recursive.
import 'dart:js';
/// A workaround to deep-converting an object from JS to a Dart Object.
Object jsToDart(jsObject) {
if (jsObject is JsArray || jsObject is Iterable) {
return jsObject.map(jsToDart).toList();
}
if (jsObject is JsObject) {
return Map.fromIterable(
getObjectKeys(jsObject),
value: (key) => jsToDart(jsObject[key]),
);
}
return jsObject;
}
List<String> getObjectKeys(JsObject object) => context['Object']
.callMethod('getOwnPropertyNames', [object])
.toList()
.cast<String>();
I can get a callback function on an instance to work in a pure Typescript project. When I try to do the same thing in a Node project using Typescript, when I refer to this, it no longer points to my instance. Is Node causing this issue, or am I missing something else. I am new to Node and we are trying to figure this out for a new project.
Example: (I moved some of the code around to simplify the example)
server.ts:
import controller = require('./controllers/locationController');
var locationController = new controller.LocationController(LocationModel.repository);
var unbound = locationController.test;
unbound(); --when this calls locationController.test, that test method no longer has access to anything on this
locationController.ts:
export class LocationController {
private _x = 1;
_repository: mongoose.Model<locationModel.ILocation>;
constructor(repository: mongoose.Model<locationModel.ILocation>) {
this._repository = repository;
}
test = () => {
var t = this._x; --This is where the issue is. _x is undefined even though I am using the arrow notation
}
}
Is Node causing this issue, or am I missing something else
Your understanding of arrow and this are correct. Therefore the code you have provided works fine:
Solution
The error exists in some other piece of code. Track that down.
All mootools more modules are included in my app, but I would like to remove the ones I am not using. Is there a quick way to know which modules I am using starting from the script depending on mootools more?
no easy way, I am afraid. you can spy on stuff while your app runs so you can get some usage/coverage stats but because mootools is prototypal, the extensions to Array/String/Function/Date etc that more does may be more complicated to catch.
To catch classes that have been instantiated, build a list and use something like that:
Object.monitor = function(obj, match){
var keys = (function(obj){
// include from prototype also, any function.
var keys = [], key;
for (key in obj) typeof obj[key] === 'function' && keys.push(key);
return keys;
}(obj)),
log = function(what, method){
// more use goes red in console.
console.log(obj, method, what);
},
counters = {};
keys.forEach(function(key){
var orig = obj[key];
Object.defineProperty(obj, key, {
get: function(){
key in counters || (counters[key] = 0);
counters[key]++;
key.test(match) && log(counters[key], key);
return orig;
}
});
});
};
var protos = [Fx.Reveal, Fx.Slide, Request.JSONP]; // etc etc - stuff you are unsure of.
protos.forEach(function(klass){
Object.monitor(klass.prototype, /\$constructor/);
});
new Request.JSONP({});
as soon as any of these items gets instantiated OR extended, the constructor will get referenced and you will get the log to show it. http://jsfiddle.net/dimitar/8nCe6/ - this will instantiate Request.JSONP().
I wrote the Object.monitor to spy on methods being called on a particular instance but the same principle applies. The console formatting only works nice in FireBug and WebInspector - native FF console needs to be made simple.
http://fragged.org/spy-on-any-method-on-an-object-and-profile-number-of-times-called_1661.html
you can use it to spy on say, Array.prototype or any suchlike as well - but the difficulty is the code complexity of more. Hard to really nail it down :(
probably easier to concatenate all your scripts EXCEPT for mootools-more then grep for known classes / methods from the Types.
Did you compress the file?
If you haven't removed the original comments from your build, there should be a link at the top of your file with a list of the included packages and a link. e.g.
// Load this file's selection again by visiting: http://mootools.net/more/065f2f092ece4e3b32bb5214464cf926
If you don't have the link, but other comments are included, search the file for script: and you should get a list back of all the included packages.
I'm using following code in JScript (WSH) to connect to local registry using WMI: var registry = GetObject('winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\default:StdRegProv'); and that works.
Then I have to determine if I'm allowed to delete key without really trying to delete it (e.g. perform a non-destructive check). I looked over docs and found that I need StdRegProv.CheckAccess() method. Problem is that CheckAccess returns result as out argument and I could not find VBScript's ByRef equivalent in JScript.
Somewhere in the Internet I've found that using SWbemServices.ExecMethod would help somehow, but I hadn't figured out how can I use that yet.
Could anyone provide me with code sample in JScript performing function call with argument passed by reference?
Heh, got it working.
For anyone who will need it, CheckAccess invokation in JScript looks something like this:
function CheckAccess(defKey, subkeyName, required) {
var providerName = "StdRegProv";
var funcName = "CheckAccess";
// connect to WMI
var services = GetObject("winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\default");
// get provider
var registry = services.Get(providerName);
var in_params = registry.Methods_(funcName).InParameters.SpawnInstance_();
in_params.hDefKey = defKey;
in_params.sSubKeyName = subkeyName;
in_params.uRequired = required;
var outParams = services.ExecMethod(providerName, funcName, inParams);
return Boolean(outParams.bGranted);
};