I have imported a few classes in Adonis
const User = use('App/Models/User')
const Orders = use('App/Models/Orders')
I want to be able to access one of the above classes dynamically. By that I mean a variable will hold the class I want to access. The variable will be populated by via an API call from the user.
let className = 'Orders'
How to I use the className variable to access the Orders class.
I have tried
[className].query().where('orderNumber','123').fetch()
However that does not seem to work.
Create a name -> class map:
const classes = {
__proto__: null, // to avoid people being able to pass something like `toString`
Users,
Orders,
};
// or if you don't want to use __proto__
const classes = Object.assign(
Object.create(null),
{Users, Orders}
);
and access the right class with classes[className]. Of course verify whether the class exists or not.
I have tried
[className].query().where('orderNumber','123').fetch()
However that does not seem to work.
In this context, [...] denotes an array literal, so [className] just creates an array containing className (which is a string in your example) as only element.
Avoid converting the variable to a string at all. Just use:
let className = Orders;
className.query().where('orderNumber','123').fetch()
If the class is being instantiated by an API call, use a simple switch statement:
let class;
switch (apiCall.name) {
case 'orders':
class = Orders;
break;
case 'users':
class = Users;
break;
default:
throw 'Invalid API Call';
}
class.query().where('orderNumber','123').fetch()
Easiest would be to eval(className).query().where('orderNumber','123').fetch(), but if you want to check the values existence as an actual class, you probably should implement a switch or if-else-if to check and assign className and call only if it is actually present.
Related
I am unsure of why I would exactly need to use a class here or perhaps a better way to say it is: I am not sure how a class is helpful as opposed to just forming objects on the fly.
export default class Car {
constructor(type="not specified", engine="V6") {
this.type = type;
this.engine = engine;
}
getType() {
return `the car type is ${this.type}`
}
}
main.js
import Car from Car.js;
let allCars = [];
function userSubmittedCarInfo() {
let typeValue = document.getQuerySelector('.input-type').value;
let engineValue = document.getQuerySelector('.input-engine').value;
// not sure the difference of just sending data as an object vs sending as class object?
//option 1 .... for object on the fly that I can post to server. Push it to list if I
// need a running list of all objects later on.
let obj = {
type: typeValue,
engineValue: engineValue,
}
allCars.push(obj);
//option 2... second option is create an instance of Car class
let obj = new Car(typeValue, engineValue)
fetch('url-i-am-posting-to', {
car: obj
})
}
Classes are generally useful when you want to tie together data with methods that operate on that data. Your Car here gives instances both properties on the instance (data) as well as a method that operates on the data (getType).
If you actually do want to call the getType method at certain points in the code, or if you add additional methods on the Car, having a class is quite a reasonable choice - you just have to pass in the data, and it'll return an object containing both the data and useful methods for that data.
But if you don't need methods - like in this example, it doesn't look like you're ever calling getType - then a class may well not provide any benefit, and could be considered to only be adding confusing overhead, and using an object literal would make good sense instead (arguably, even more sense).
I am currently learning JavaScript, and have a question about _variable name.
Firstly, what is the relationship between valuable name, and same valuable name with underscore? I am using this._title in getter and setter to get value from title, but I do not understand why _title can be used without declaring, and also when console this._title, it is able to show the value of title.
const movies = [];
const addMovieHandler = () => {
const title = document.getElementById('title').value;
const newMovie = {
info: {
set title(val) {
if(val.trim() === ''){
this._title = 'DEFAULT';
return;
}
this._title = val;
console.log(this)// shows the object of new movie
console.log(val)// show value of title
console.log(this._title)// also show value of title
},
get title() {
return this._title.toUpperCase();
}
}
};
newMovie.info.title = title;//setter
console.log(newMovie.info.title);//getter
movies.push(newMovie);
};
Thank you for your help!
Nagisa
Stepping back a bit, traditionally:
title = 'foo'; // assigns value 'foo' to title (set action)
console.log(title); // references title (get action)
You work directly with title, assigning a value to it directly, and when you reference it, js returns the value of it.
The concept of get and set methods is that you can add a proxy layer to the variable to write your own code to define what happens when you assign something to title (set) or reference it (get). This is most commonly used to add logic for default values or validate/scrub/format values.
So in your code, title and _title are two distinct variables that are not directly/intrinsically tied together, except by your own conventions set within title's set and get methods.
And within set and get, you do whatever you want. In this case, you are using an "internal" variable _title to hold the actual value. This can be named anything you want, but by convention, many people use the same variable name as the public one, but with a _ prefix. You don't even need to have one at all; it just depends on what your goal is.
I'm attempting to create this structure in firebase:
inMinistries
--uidOfGroup1
----0: uidOfGroup1Member
----1: uidOfGroup1Member
----2: uidOfGroup1Member
--uidOfGroup2
----0: uidOfGroup2Member
----1: uidOfGroup2Member
In the above example inMinistries is the first node, then we have uidofGroup1 which would be a uid of a Group then I want child nodes to appear like uidOfGroup1Member. There are several so I can't say exactly how many I need.
Here is my attempt to create the above:
class Firebase {
constructor() {
app.initializeApp(firebaseConfig);
this.auth = app.auth();
this.db = app.database();
this.storage = app.storage();
}
This is how I set the uidOfGroups
this.db.ref(`inMinistries/${uidOfGroup}`).set('members')
I pass a uid value I receive from another call. I set 'members' so that I could replace it with a group of members later.
I then try to create uidOfGroup1Members, uidOfGroup2Members. I get stuck on this part. If I do a set like so:
this.db.ref(`/inMinistries/${uidOfGroup}}`).set(memberId);
I can only pass the memberId once, meaning I'd need to have the full list of uidOfGroupMembers which I don't have all at once. I'd like to be able to push it like I would in an array. But if I do push:
this.db.ref(`/inMinistries/${uidOfGroup}}`).push(memberId);
then it adds an extra uid to the value before like so:
Note the above is actually using the uids. How can I achieve the original desired result I placed on top?
If you have no constraint on how you save the different uidsOfGroupMember under a specific uidOfGroup (in particular no need for using a specific "index" (i.e. 0, 1, 2)), you could use the set() method as follows:
var uidOfGroup = 'uidOfGroup1';
var uidOfGroup1Member = 'uidOfGroup1Member'; //Of course, here you can assign the value you want, e.g. -Lwk98a...
this.db.ref(`/inMinistries/${uidOfGroup}/${uidOfGroup1Member}`).set(
uidOfGroup1Member
);
var uidOfGroup2Member = 'uidOfGroup2Member';
this.db.ref(`/inMinistries/${uidOfGroup}/${uidOfGroup2Member}`).set(
uidOfGroup2Member
);
One difference between the push() and the set() methods is that push() creates a child location with an auto generated unique key, which is the cause of your problem.
I want to make an object that inherits from an other object. In constructing the descendant, i want to push some items to an inherited array without changing the parentobject.
Say I have an object called basket:
function Basket(){
}
Then i fill it like this:
Basket.prototype {
“price”: 5,
“contents” : [“apple”, “orange”, “grape”]
}
Now i want to extend this. I want to add some properties and change some. I did this:
function BigBasket(){
this.price = 6; // change a property. This goes well, when an instance is created, price is still 5 in prototype and also in instances of Basket and it is 6 in the instance that is created from this descendant.
this.greetingcard = “Congratulations” // add a property. Goes well
Now i want to add an item to the contents-property but only in the descendant instances.
This goes wrong:
this.contents.push(“banana”);
It seems this.contents contains a reference to the array of the prototype so when pushing a banana to it, means that instances of both Bigbasket and Basket get a banana in their contents as well. Therefore i first made a copy of the Basket.contents (the parent contents) like this:
this.contents = Object.getPrototypeOf(this).contents.slice(); // seems __proto__ is deprecated, so using getPrototypeOf here and then pushed the banana:
this.contents.push(‘banana’);
}
This seems to be working, but is this the right way? I know array is an object as well, so i tried this:
this.contents = Object.create(Basket.prototype.contents);
this.contents.push('banana');
This works too and seems a more generic way. Furthermore in Chrome the item that was pushed last was a property of only the descendant while the rest of the array-items were properties of the prototype. Seems elegant to me.
Still, this looks a bit clumsy to me. Am i doing this all wrong? Tried to find out but couldn’t find anything on the topic of array’s in extending objects. Is there a way of making descendants where all properties are copied and not referenced when instanciated?
Thanks!
You can try something like this:
Instead of putting price and content on prototype, make them as properties of Basket.
Inherit BigBasket and set its prototype as instance of Basket. This will give you access to properties of Basket.
Define a private variable content in BigBasket whose job will be to maintain the child's content.
Add a setter function to mutate this variable
addContent: Add new values to child's content
removeContentByIndex: to remove value based on index.
getContent: This will return a copy of content to nullify side effect. This will also allow you to have custom definition of content. In this case, its own content + parent's content
this will allow you to define an API to communicate with content and also allows you to create a restrict data that is exposed. Exposing everything can cause issues. Exposing what is required is always better.
Note: Having objects on prototype can cause issues as objects will have side effect. You should use Parent's values as default values only.
function Basket() {
this.price = 5;
this.contents = ["apple", "orange", "grape"]
}
function BigBasket() {
const content = [];
this.price = 6;
this.greetingcard = "Congratulations";
this.addContent = function(value) {
content.push(value);
}
this.removeContentByIndex = function(index) {
content.splice(index, 1);
}
this.getContents = function() {
return [].concat(this.__proto__.contents, content);
}
}
BigBasket.prototype = new Basket();
const bb1 = new BigBasket();
const bb2 = new BigBasket();
bb1.addContent('banana');
console.log(bb1.getContents(), bb2.getContents())
I hope I make my question clear.
I have a few objects which I have created with a property called address. For example, Obj1 has address 0x0000, Obj2 has address 0x0004 and so on.
There is a list of random input addresses which I need to process. Once the input address is one of the object address (if addr=0x0000||addr=0x0004....), then a function will be automatically loaded.
Currently, I am comparing it by a list of Object addresses, which I think is a waste of iteration. Is there any way, I can access it by index? For example, once I enter an input address of 0x0004, a function will be run directly.
edit : Thanks for all your answers :) I have a clearer idea now
You got 2 choices:
Use switch to define all functions:
switch (input){
case '0x0000': function(input){}; break;
case ...
}
Use a predefined map:
var functionMappings = {
'0x0000': function_1,
'0x0001': function_2,
};
if(functionMappings[input]) {
functionMappings[input](input);
}
I would prefer the second example, because it can be created dynamically in the runtime.
Update:
You can create your functionMappings dynamicaly like this:
var functionMappings = {// create first entries, or defualt functions
'0x0001': function_1,
'0x0002': function_2
};
if(condition_x) { // add new or overwrite existing functions
functionMappings[0x0005] = function_5;
}
Because this is an map, you can even overwrite default function definitions, if you need.
Iterate once and put all addresses as keys to an object:
var addresses = {};
for(var i=0;i<objList.length;i++){
addresses[objList[i].addr] = {};
addresses[objList[i].addr].fn = correspondingFunction
// you can even attach the corresponding object to it
// addresses[objList[i].addr].obj = addresses[objList[i].addr];
}
I use a loop for the example but you can do it any way that suits you
Then you have a list of your objects keyed by their address, and you can fetch them by it:
function getAddrFunction(addr){
if(addresses[addr] !== undefined){
return addresses[addr].fn;
}
return null;
}