I'm trying to make the following code works without any luck, and I can't see a clear solution on how to do it.
export default {
model: null,
set: function (data) {
this.model = data
},
account: {
update: function (data) {
this.model.account = data
}
}
}
My issue here is that account.update fails because this.model does not exists. I suspect that the sub object gets a new this, hence my issue, but I don't know how to fix it.
I tried the alternative here :
export default (function () {
let model = null
function set (data) {
this.model = data // I also tried without the `this.` but without any luck too
},
function updateAccount(data) {
this.model.account = data
}
return {
'model': model,
'set': set,
'account': {
'update': updateAccount
}
}
})()
But apparently the same rule applies.
Maybe it's worth noting that I'm using Babel to compile ES6 down to ES5 javascript.
It fails because this refers (in this case) to the window object. Reference the object itself like this:
let myModel = {
model: null,
set: function (data) {
myModel.model = data // reference myModel instead of this
},
account: {
update: function (data) {
myModel.model.account = data // reference myModel instead of this
}
}
}
I would take an approach similar to your alternative solution. There is however no need to wrap your code in an IIFE, ES2015 modules are self-contained; you don't need an IIFE for encapsulation.
let model = null,
set = (data) => {
model = data;
},
updateAccount = (data) => {
if (!model) {
throw('model not set');
}
model.account = data;
};
export default {
model,
set,
account: {
update: updateAccount
}
};
Since you are already using Babel, I also used arrow functions and the new shorthand properties to make the code a little shorter/readable.
Related
I have a particular scenario where I want to access data from "this" while looking through an array that is also defined on my Vue component. Example:
data () {
return {
question: [],
inputList: [],
form: {}
}
},
methods: {
onSubmit: function () {
let predictionParams = {}
this.inputList.forEach(function (element) {
predictionParams[element.detail] = this.form[element.detail]
})
}
Error:
this.form is not defined in the context of the forEach loop
Question:
What is the idiomatic JS way of handling a case like this? I run into this quite often and I always feel like I come up with sketchy solutions, or at the very least something easier could be done. Any help on this would be great.
Many built-ins, including forEach include an optional 'this' binder:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
use that to your advantage:
this.inputList.forEach(function (element) {
predictionParams[element.detail] = this.form[element.detail]
},this)
supported since ie9
arrow function syntax avoids rebinding this
this.inputList.forEach(element => {
predictionParams[element.detail] = this.form[element.detail]
})
You can use Arrow function https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
It will binding this into the function
data () {
return {
question: [],
inputList: [],
form: {}
}
},
methods: {
onSubmit: () => {
let predictionParams = {}
this.inputList.forEach((element) => {
predictionParams[element.detail] = this.form[element.detail]
})
}
I saw this code today, which does something I've never seen before. It has an object which itself has an unlabeled property that is a function.
emails = {
type: EmailType,
args: { id: { type: GraphQLID } },
resolve(parentValue, args) {
const query = `SELECT * FROM "emails" WHERE id=${args.id}`;
return db.conn.one(query)
.then(data => {
return data;
})
.catch(err => {
return 'The error is', err;
});
}
}
}
I'd like to know more about this, but I have no idea what the proper keyterm for this is, and searching "function as property js" only yields really obvious stuff (ie {someProp: () => 42}).
I'm certain that both:
A. If I knew the right key term, it would be really easy to learn more and
B. The only way to make this keyterm easier to find is to have something someone would actually search lead to it. To that end, I'll include some extra SEO:
object has function but not at prop
function inlined in object
function in object
object has a function but it's not a prop
no propname for function
Anyways:
What is this called, and where can I find more information on it?
EDIT: Got links to docs. One thing to denote is the differences between
// these are the same, I think
const eg1 = { someFn() {} }
const eg2 = { someFn: function() {} }
// this is different in scope... I think
const someFn = () => {};
const eg3 = { someFn };
It is a Shorthand method name.
{ method() { /*...*/ } }
is equal to:
{ method: function() { /*...*/ } }
Where do you correctly place local functions in vue 2.x?
I could just place them in the "methods" object, but I'd like them to be completely local to the instance if thats possible.
Sort of like this in Plain JS :
window._global = (function () {
function _secretInsideFunct(){
return "FooBar";
}
var __localObject = {
outsideFunct : function () {
return _secretInsideFunct();
}
}
return __localObject;
}());
..where _global._secretInsideFunct() wouldnt be accessible anywhere else but from inside the _global object.
In this specific case I want to make a function that creates an array object if it doesn't exist.. Something like:
function CreateOrSet (workArray, itemName, itemValue ){
var salaryRow = self.Status.Rows.find(r => r.recordID == itemName);
if (!salaryRow) {
salaryRow = { recordID: itemName, recordAmount: 0, recordName: "Løn" };
self.Status.Rows.push(salaryRow);
}
salaryRow.recordAmount = itemValue ;
}
..but a general approach for these cases is better :)
Now this function doesn't looks like a utility or helper function, but relate to a state, Status.Rows. If I were you, I will define it as close as to the state or the module that the state being used.
If the state will be used across the app, maybe I will define it in entry file, index.js or app.vue.
Or If you are using vuex, you can define it as an vuex action. So you may do something like this:
const store = new Vuex.Store({
state: {
status: {
rows: []
},
mutations: {
pushRow (state, salaryRow) {
state.status.rows.push(salaryRow)
},
changeAmount (state, id, amount) {
const salaryRow = state.status.Rows.find(r => r.recordID === id)
salaryRow.recordAmount = amount
}
},
actions: {
createRow (context, itemName) {
const salaryRow = { recordID: itemName, recordAmount: 0, recordName: "Løn" };
context.commit('pushRow', salaryRow)
}
}
})
You can put all of the code to a single action, it is just an idea, how you organize your code depend on your needs.
I'd like to avoid let that = this; because it seems to be a dirty solution. Is it e.g. possible to use .bind(this) anyhow?
My current code:
// ...
componentDidMount() {
let that = this; // <- how to avoid this line?
this.props.myService.listensTo('action', (data) => {
that.handleData(data);
});
}
handleData(data) {
// handle data
}
// ...
Thanks in advance!
Basically arrow functions will help with this and since React-Native doesnt have to deal with browser compatibility you can define you're functions like this:
handleData = (data) => {
this.setState({ data });
}
You won't ever have to .bind or that=this if you use this.
this is already bound because of the arrow function you've used.
// ...
componentDidMount() {
this.props.myService.listensTo(
'action',
(data) => this.handleData(data)
);
}
handleData(data) {
// handle data
}
// ...
have been using a pretty much loving Crockford's constructor, but, having problems adding scoped functions to the object:
'use strict';
var Constructor = function( params ) {
let config = params,
data = params.datum,
action = function(a,b) { return config.actions[a](b); };
return Object.freeze({
action: action
});
};
var cns = Constructor({
datum: 123,
actions: {
getData: function(b) { return data; }
}
});
cns.action('getData',0);
get Uncaught ReferenceError: data is not defined.
how do I have a function as an argument to the constructor and have that function have the scope of object?
If you are following Crockford's private members in JavaScript post, then getData should be a "privileged" function (a function that has access to private members such as data). Therefore, this function should follow the "privileged" pattern given in his post (JSFiddle example).
var Constructor = function (params) {
var config = params;
var data = params.data;
// Privileged function pattern:
// By using a closure, this method has access to private members.
this.getData = function (b) {
return data;
};
};
// Note: Changed to `new` in order to instantiate the class
var cns = new Constructor({
data: 123
});
console.log(cns.getData(0));
the easiest way seems to be to manually pass object guts to the function, either with call or as an extra argument. since I'm dodging this, am using the extra argument, here self. self is not exposed to the world at large, only to the functions that need to see it.
'use strict';
var Constructor = function( params ) {
let config = params,
data = params.datum,
self = { data: data },
action = function(a,b) { return config.actions[a](b,self); };
return Object.freeze({
action: action
});
};
var cns = Constructor({
datum: 123,
actions: {
getData: function(b,s) { return s.data; }
}
});
cns.action('getData',0);