For example.
We have a couple of ES6 module imports, say:
import Module1 from './module_1';
import Module2 from './module_2';
Am using Babel to transpile ES6 into ES5
Have another function, which given a string, returns a reference to the imported ES6 module:
getModule(name) {
switch(name) {
case "Module 1":
return Module1;
case "Module 2":
return Module2;
default:
return null;
}
}
The naming convention is pretty straight forward and consistent
So how to remove the manual switch statement ?
Initially I thought, we can get away with using eval. something like:
getModule(name) {
// removes spaces. so "Module 1" to "Module1"
const ref = name.replace(/\s+/g, "");
return eval(ref);
}
But Babel changes the variable names etc
and has pulled the carpet from under my feet.
Just to demonstrate a non-transpiled example works with:
var foo = function() { console.log("called foo") }
var bar = function() { console.log("called bar") }
eval("foo")() // logs "called foo"
eval("nope") // throws ReferenceError: Can't find variable: nope
Is it possible to get a hash of imports in a file, called say localImports ?
so that we can write:
getModule(name) {
// removes spaces. so "Module 1" to "Module1"
const ref = name.replace(/\s+/g, "");
return localImports[ref];
}
How to implement such a function using ES6 and Babel ?
Also as a bonus, is it possible without using eval ?
This worked for me:
Import the modules.
import Module1 from './module_1';
import Module2 from './module_2';
Cache the modules in local scope with whatever name you want. In this case I use the same name: Module1, Module2.
setModules(){
this.Module1 = Module1;
this.Module2 = Module2;
}
Get the reference to the module using a reference made in local scope.
getModule(name) {
return this[name]; //e.g. name = 'Module1'
}
If you're compiling the imports to require using Babel, you could just use require directly and make a map:
const modules = {
'Module 1': require('./module_1'),
'Module 2': require('./module_2')
};
function getModule(name) {
return modules[name];
}
Related
Due to old browser support, we all use babeljs to transpile ES6 into ES5. When babel compiles a class which is extended from another class. There is a part of compiled code like this:
function _createSuper(Derived) {
var hasNativeReflectConstruct = _isNativeReflectConstruct();
return function _createSuperInternal() {
var Super = _getPrototypeOf(Derived),
result;
if (hasNativeReflectConstruct) {
var NewTarget = _getPrototypeOf(this).constructor;
result = Reflect.construct(Super, arguments, NewTarget);
} else {
result = Super.apply(this, arguments);
}
return _possibleConstructorReturn(this, result);
};
}
I know the _createSuper function is to create a function wrapping the process of calling super class which binds this as sub class's instance so that the sub class can inherit its super class's properties. To complete this purpose, what we need to do is only let result = Super.apply(this, arguments). But the codes check if the environment support Reflect and uses Reflect.construct preferentially. I actually don't know why we need result = Reflect.construct(Super, arguments, NewTarget) and what does it do. Can someone explain it in detail?
I've been making a discord.js bot following the official guide.
I have all my commands in the /commands folder as advised.
Then I followed the course to create a currency system with sequelize, following this page from the same guide.
I have a balance.js file inside the commands folder, but when I'm calling it, it gives me this error:
TypeError: currency.getBalance is not a function
I've defined the function in my app.js file, but how can I export it (or use it) inside the balance.js which is called by the app.js file?
This is the function defined in the main file app.js:
Reflect.defineProperty(currency, 'getBalance', {
value: function getBalance(id) {
const user = currency.get(id);
return user ? user.balance : 0;
},
});
This is balance.js:
module.exports = {
name: 'balance',
description: 'Informs you about your balance.',
cooldown : 10,
guildOnly : true,
aliases: ['bal', 'cur', 'gem', 'gems'],
execute(message, args) {
const Discord = require('discord.js');
const { Users, CurrencyShop, UserItems, CardBase, UserCollec } = require('../dbObjects');
const currency = require('../app.js')
async () => { const storedBalances = await Users.findAll();
storedBalances.forEach(b => currency.set(b.user_id, b));
UserCollec.sync(); }
const target = message.author;
return message.channel.send(`${target} has ${currency.getBalance(target.id)}<:Gem:756059891465977886>`);
},
};
EDIT:
I progressed. Now I understand that I have to import the currency variable, which has been declared as a new Discord.Collection() in app.js.
I need to refer to this variable in a module and this module doesn't seem to see it as a collection. How do I import it?
I have a JSON response I get from backend which I'm displaying as {{ response | json }}. There's a copy to clipboard option where i need to copy the contents of response. I have the following code
copy(response){
let val = response;
const selBox = document.createElement('textarea');
selBox.style.position = 'fixed';
selBox.style.left = '0';
selBox.style.top = '0';
selBox.style.opacity = '0';
selBox.value = val;
document.body.appendChild(selBox);
selBox.focus();
selBox.select();
document.execCommand('copy');
document.body.removeChild(selBox);}
This copies as [object object] since response is an object. I can copy it converting the response to a string as let val = JSON.stringyfy(response) . But this does not copy it in a formatted way I display it, instead copies the json in one single line like a string. So how to copy to clipboard a JSON object in a proper formatted way?
There is a built-in Clipboard class in the angular cdk that makes this a little easier to do. You should also use the space parameter with your JSON.stringify
First npm install the #angular/cdk package if you don't have it already.
In your #NgModule import ClipboardModule
import { ClipboardModule } from '#angular/cdk/clipboard';
#NgModule({
imports: [
ClipboardModule
],
})
In your component's typescript file import the Clipboard class
import { Clipboard } from '#angular/cdk/clipboard';
#Component({ /* ... */ })
export class MyComponent {
constructor(private clipboard: Clipboard) { }
public copy() {
// replace this object with your data
const object = {abc:'abc',xy:{x:'1',y:'2'}}
// Note the parameters
this.clipboard.copy(JSON.stringify(object, null, 2));
}
}
In your component's template
<button (click)="copy()">
Copy Data
</button>
The result of stringifying {abc:'abc',xy:{x:'1',y:'2'}} when pasted:
{
"abc": "abc",
"xy": {
"x": "1",
"y": "2"
}
}
With reference to the answer linked by x4rf41, you can make your stringify function whitespace your JSON with let val = JSON.stringify(response,null,2). If you want syntax highlighting, you can use user123444555621's function.
A much neater way to copy text is to add an event listener for the copy event, and set the clipboardData dataTransfer object:
window.addEventListener('copy', (event) => {
if(copying){
let val = JSON.stringify(response,null,2);
event.preventDefault(); //stop the browser overwriting the string
event.clipboardData.setData("text/plain",val); //encode the appropriate string with MIME type "text/plain"
copying = false;}
});
copy = function (){
copying = true;
document.execCommand('copy');}
If you are using the afore-mentioned syntax highlighting function, you probably want to specify MIME type "text/html". Hopefully the formatting options in the linked answer suit your needs.
Inside webpack.config.js I have computed a javascript map that I'd like import as a module in the browser. I could write the data to disk and then read it back with e.g https://github.com/webpack/json-loader, but is there any more elegant ways to do this in-memory?
webpack.config:
var config = {
key: 'data'
}
// do something with webpack loaders
some.file.that.is.executed.in.browser.js:
var config = require('config')
window.alert('Config is', config.key)
webpack loaders are file preprocessor, thus there needs to be the file that you import. So create a dummy file and use json-string-loader to override the contents.
Create an empty config.json to your project.
In webpack.config.js:
var appConfig = {
key: 'data'
}
...
loaders: [
{
test: /config.json$/,
loader: 'json-string-loader?json=' + JSON.stringify(appConfig)
}
In browser:
var appConfig = require("./config.json");
// => returns {key: 'data'}
I could write the data to disk and then read it back with e.g
https://github.com/webpack/json-loader, but is there any more elegant
ways to do this in-memory?
Why? You can just do whatever you need in config.js (instead of static json) and just return a result:
var data = 'foo' + 'bar';
module.exports = {
key: data
}
I have a Component that has an injected service, which makes an Ajax call. I can receive the JSON data successfully and can dump it into the console after the promise "THEN" returns.
Here's my component. I can see the dumped data, but how do I set the component properties with that JSON and have it accessible in the template? Also, why can't I use "this.get" in my function below?
import Ember from 'ember';
export default Ember.Component.extend({
attr_types: Ember.inject.service('svc-attrtypes'),
atype_list: [],
actions: {
getATypes: function() {
this.get('attr_types').getTypes().then(function(json){
console.log(json);
this.atype_list = json;
console.log(this.atype_list);
// below returns: TypeError: this.get is not a function
this.get('atype_list').pushObjects(json);
});
}
}
});
In my template I have this:
{{#each atype_list.alltypes as |a|}}
<li>{{a.attr_type}} - {{a.attr_type_desc}}</li>
{{/each}}
If I manually place my JSON into the atype_list it shows perfectly on the template. But if I try to set it after my Ajax returns, nothing shows, except for in the console output.
I appreciate any help. I am sure I a missing something simple. ( or more likely, I'm just going about this all wrong)
This changed with anonymous function passed to then. You have to save this or use es6 arrow function syntax.
import Ember from 'ember';
const { service } = Ember.inject;
export default Ember.Component.extend({
attrTypes: service('svc-attrtypes'),
atypeList: [],
actions: {
// es6 version
getATypes(){
this.get('attrTypes').getTypes().then(array => {
this.set('atypeList', array); //replaces original array
this.get('atypeList').pushObjects(array); // adds array's elements to the end
});
}
// es5 version
getATypes: function () {
var _this = this;
this.get('attrTypes').getTypes().then(function(array){
_this.set('atypeList', array);
}
}
}
});
You wrote that you are new to ember, so I added little more syntax sugar. Also check ember-cli if you don't know about that already.