How to reference data around function in object without traversing entire object? - javascript

Having an object similar to:
const data = {
tasks: {
projects: [
name:'Project Name',
filters: [
{
name:'First Project Filter',
checked:false,
onChange:(event) => {
console.log(this.checked)
}
},
...
],
...
],
...
},
...
}
The problem at hand is how to reference the checked property without drilling through the entire object.
In the case above, it throws an error because this is undefined, so referencing this.checked is invalid.
I could extract from the event data properties so that I can get the
whole reference such as tasks.projects[0].filters[0].checked, but I
am wondering if an easier method is available.
The ideal solution would be a way to reference the surrounding properties of the function without traversing the entire object. Surely the function has a way to know that it is inside of an object so maybe something like parent().checked ?
If relative: I am using node.js and react to use this object to render a filtered sidebar that works with context to filter the data-set. I don't think that is relative as this seems like a pure JavaScript OOP situation.

Related

Access data from template to Vue Instance

I'm very new to vue, so this is properly a basic question. I have a value in my template from an parsed object prop like this:
<h1>{{myval.theme}}</h1>
This gives and display the value in the browser. However, I need to obtain the value and store it in the data section of the instance. How can I store the data in the "getTheValue" data string? This is what I currenct have, and this does not work:
props: {
myval: Object
},
data() {
return {
getTheValue: this.myval.theme
};
},
The best way its to use computed here
computed: {
getTheValue() {
return this.myval.theme
}
}
and call it same way:
this.getTheValue
its best solutions - cached, non-reactive
also if you still want to use data you can assign in lifetime-hooks like:
mounted() {
this.getTheValue = this.myval.theme
}
But its crude solution, and I highly recommend to use computed variant

data with function return vs. return plain data object

When I started with Vue.js I read about a case where you return a data property with return and sometimes without. I cannot find that article anymore that's why I'm asking here.
That's how I use it today
data: function () {
return {
myData : "data"
}
},
But that's how I see it in documentation very often - don't know the difference anymore:
data: {
myData: "data"
},
https://vuejs.org/2016/02/06/common-gotchas/#Why-does-data-need-to-be-a-function
Why does data need to be a function?
In the basic examples, we declare the data directly as a plain object. This is because we are creating only a single instance with new Vue(). However, when defining a component, data must be declared as a function that returns the initial data object. Why? Because there will be many instances created using the same definition. If we still use a plain object for data, that same object will be shared by reference across all instance created! By providing a data function, every time a new instance is created, we can simply call it to return a fresh copy of the initial data.

Data binding on JavaScript HTMLElement property in Polymer

Making an SPA using Polymer, and I need my custom components to all use a common custom component which represents my backend API and is responsible of GET-ting/POST-ing data from/to the API. It also serves as a "cache" and holds the data to display. This way, all the components that have access to this single element will share the same data.
So what I want to do is this... :
<my-api
users="{{users}}"
products="{{products}}">
</my-api>
...but programmatically, as <my-api> is not declared in all of my components but once in the top one and then passed down through the hierachy by JavaScript:
Polymer({
is: 'my-component',
properties: {
api: {
observer: '_onApiChanged',
type: HTMLElement
},
products: {
type: Array
},
users: {
type: Array
}
},
_onApiChanged: function(newVal, oldVal) {
if (oldVal)
oldVal.removeEventListener('users-changed', this._onDataChanged);
// Listen for data changes
newVal.addEventListener('users-changed', this._onDataChanged);
// Forward API object to children
this.$.child1.api = newVal;
this.$.child2.api = newVal;
...
},
_onDataChanged: function() {
this.users = this.api.users; // DOESN'T WORK as 'this' === <my-api>
this.products = this.api.products; // Plus I'd have to repeat for every array
}
});
Does Polymer offers a built-in way to do this ? Can I create a double curly braces binding programmatically ?
I would likely architect this slightly differently: passing down the products/users arrays declaratively taking advantage of Polymer's binding system. Or you could write your my-api element in such a way that they all share state and the first declared one is the primary while future declared ones are replicas. This would let you declare them wherever you need them and bind to the values via Polymer's normal ways.
But to answer your question, there's currently no way to easily programmatically setup the same kind of binding without using private Polymer APIs.
To avoid repeating as much and for the binding issue you were having you could use Polymer's built-in listen and unlisten methods:
Polymer({
is: 'my-component',
properties: {
api: {
observer: '_onApiChanged',
type: HTMLElement
},
products: {
type: Array
},
users: {
type: Array
}
},
_onApiChanged: function(newVal, oldVal) {
var apiProperties = ['users', 'products'];
if (oldVal) {
apiProperties.forEach(function(prop) {
this.unlisten(oldVal, prop + '-changed', '_onDataChanged');
});
}
// Listen for data changes
apiProperties.forEach(function(prop) {
this.listen(newVal, prop + '-changed', '_onDataChanged');
});
// Forward API object to children
this.$.child1.api = newVal;
this.$.child2.api = newVal;
...
},
_onDataChanged: function() {
this.users = this.api.users; // `this` should be the element now
this.products = this.api.products;
}
});
Given how this is a common pattern you're doing, you could probably get a lot of benefit out of extracting some of these things into a Behavior that abstracts away the binding/unbinding and API element forwarding.
Another optimization you may could make work would be to to look at the event passed to _onDataChanged to see if you can infer which value changed and update your corresponding property. This could prevent you needing to add a line for every property.
I ended up using an other solution. Instead of manually passing the top <my-api> element down the hierarchy any element that needs access to this shared data declares its own <my-api>.
Then in the <my-api> element's declaration I made that all instances use the same arrays references. So whenever I update one they all get updated, and I don't have to pass anything down the HTML hierarchy, which makes things a LOT simpler.

Load includes on existing model

I'm trying to load includes on an existing model in sequelize. In express we pre check the models to see if they exist in the middleware.
So once we're in the actual "controller" we want to run some includes on that existing model that is passed in.
req.models.item.incude([
{model: Post, as: 'posts'}
])
Is there any way to accomplish this?
EDIT:
I know we can do something like this.
return req.models.item.getThing()
.then(function (thing) {
req.models.item.thing = thing;
return req.models.item;
});
But:
My expansions for includes are a dynamic property that come via url parameters, so they are not know ahead of time.
It I return the above you will not see the "thing" in the response. I need it nicely built as part of the original instance.
Something like a .with('thing', 'other.thing'); notation would be nice. Or in the case of sequelize .with({include: ...}); or .include([{model: ...}]);
If the variable req.models.item is already an Instance but without its other related instances ("includes"), then you could include them using something like the following code:
Item.findAll({
where: req.models.item.where(),
include: [{
model: SomeAssociateModel,
}]
})
.then(function(itemWithAssoc) {
// itemWithAssoc is an Instance for the same DB record as item, but with its associations
});
See here for some documentation. See here for a script demo'ing this.
Update: Given the instance, how do I just get the associated models?
To do this just use the automatically generated "getAssociation" getter functions, e.g.:
function find_associations_of_instance(instance) {
return instance.getDetails();
}
I've updated the script to include this as an example. For more information on these functions, see the SequelizeJS docs.

Ember Data - Get parent value from child

I have a widget model which has a shallow parent-child relationship. A given widget may be a "root" widget and not have any parent, or it may be a child widget which has a parent.
The ember data model looks like this:
export default DS.Model.extend({
name: DS.attr('string'),
parentWidget: DS.belongsTo('widget', { async: true, inverse: null }),
isSubWidget: DS.attr('boolean')
})
I'm trying to add a "displayName" property that will show the name for root widgets, or "parent name - child name" for child widgets
displayName: Ember.computed('name', 'parentWidget.name', 'isSubLob', function() {
if this.get('isSubWidget') {
return "#{this.get('parentWidget.name')} - #{#get('name')}"
}
else {
return "#{this.get('name')}"
}
})
This is not working, however. The child lob's displayName always comes as
undefined - WidgetName
The json is being returned like so:
{
"widgets": [
{
"id": 2,
"name": "Widget Name",
"is_sub_widget": true,
"parent_widget_id": 1
},
...
}
For the record, all the records are being returne by the json at the same time.
I feel like Ember should be asyncronously resolving the parent widget and the string should be updated as well, however it doesn't seem to be working. Any idea what I'm doing wrong here?
I would say you have two issues:
You're not declaring an inverse to your parentWidget relationship, which means that Ember Data is guessing the inverse (and likely guessing wrong). You should change that declaration to look like this, just to be sure:
parentWidget: DS.belongsTo('widget', { async: true, inverse: null }),
I doubt that will fix your issue, but it's good practice.
You're not waiting for your promise to resolve before trying to use the name. You've specified the parentWidget relationship as being asynchronous, which means that #get('parentWidget') will not return a model. It's going to return a promise that will eventually resolve to your model. Normally this would be fine as the computed property would just recompute when the promise resolves, except that you're not watching the proper key.
/* PS: Assuming that your comma was misplaced on this line */
displayName: Ember.computed('name', 'parentWidget', function() {
^^^^^^^^^^^^
As seen, you're only watching the parentWidget property. So if the name property on the parentWidget every updates, you won't be notified. Change that line to this and you should be good to go:
displayName: Ember.computed('name', 'parentWidget.name', function() {
Just keep in mind that the first few times through, parentWidget.name will still be undefined. It won't be the value you want until the promise resolves, which means the computed property could run several times before it does resolve.

Categories

Resources