Why some of the variables are not changed in the nested tag, in RiotJs? - nested

I have a simple nested tag:
<nested-tag>
<p>myTitle: {myTitle}</p>
<p>{myKeyword}</p>
this.myTitle = opts.title;
this.myKeyword = opts.keyword;
</nested-tag>
You can see I assign the opts.title and keyword to two new variable myTitle and myKeyword.
Then I use it in a loop of a parent tag:
<my-tag>
<input type="text" onkeyup={search} value={keyword} />
<ul>
<li each={items}>
<nested-tag title={title} keyword={parent.keyword}></nested-tag>
</li>
</ul>
this.keyword = ""
var initItems = [{ title: "aaaa"}, { title: "bbbb"} ]
this.items = initItems
this.search = function(event) {
this.keyword = event.target.value;
this.items = initItems.filter((item) => item.title.indexOf(this.keyword) >=0 );
}
</my-tag>
You can see I passed the parent.keyword to nested-tag as keyword variable.
When I input something to the text input, the keyword will be changed, so the <nested-tag> will be recreated with the new parent.keyword.
But it's not, the {myKeyword} of nested-tag is always empty. I have to rewrite it with directly opts.keyword invocation:
<nested-tag>
<p>opts.title</p>
<p>opts.keyword</p>
</nested-tag>
And it's working well now.
I'm not sure why and how to fix it? Do I have to always use opts.xxx in the nested tags?
A live demo is here:
http://jsfiddle.net/3jsay5dq/10/
you can type something to the text input to see the result

The javascript in your component nested-tag gets run when instantiating the component. So, when the component is getting generated, the myTitle and myKeyword will be initialized with whatever opts are passed in. But, on update, the myTitle and myKeyword are still pointing to the values set during instantiation. The cleanest way to go about it is to use opts[key] as they will always reflect what is being passed to the component. If you insist on using your own local properties, then you could modify your component like this:
<nested-tag>
<p>myTitle: {myTitle}</p>
<p>{myKeyword}</p>
// this will run every time there is an update either internally or from a passed opts
this.on('update', () => {
this.myTitle = this.opts.title;
this.myKeyword = this.opts.keyword;
})
// this will only run once during instantiation
this.myTitle = opts.title;
this.myKeyword = opts.keyword;
/*
// could be refactored to
this.setMyProps = () => {
this.myTitle = this.opts.title;
this.myKeyword = this.opts.keyword;
}
// bind it to update function
this.on('update', this.setMyProps)
// run once for instantiation
this.setMyProps()
*/
</nested-tag>

Related

React setState on mirrored states

this.state = {
old: null,
new: null
}
componentDidMount() {
// get data
this.setState({old: data, new: data})
}
updateData() {
// some code
this.setState({new: newData})
}
Above code updates both old and new inside updateData() what i want is to get data and store in 2 different variable (old & new), update new with user input and compare/send to server etc..
EDIT: Input change part
<label for="pname">
Min: {this.state.old.parameters[i][1]}
</label>
<input
name={"p-" + item[0]}
className="form-control"
value={this.state.new.parameters[i][1]}
onChange={e => this.handleChange(e, i, 1)}
/>
Handle Change:
handleChange(e, i, x) {
let temp = this.state.new;
temp.parameters[i][x] = e.target.value;
this.setState({ new: temp });
}
EDIT: Here is a simple example to describe my issue. When you change first input all other inputs are also changing where they shouldn't
codesandbox
Upon setState call, the original contents have to be retained too, which can be done by using {...this.state,//and any parameter changes(such as new:newData etc)}. Also, the issue was regarding Shallow and Deep copying of objects in js. Assigning objects, for example - let temp={...this.state.new} makes Shallow copy of the object and the both references point to the same object! I have made necessary changes, hope it works!
Handle Change :
handleChange(e, i, x){
let temp = JSON.parse(JSON.stringify(this.state));
temp.new.parameters[i][x] = e.target.value;
this.setState({...this.state, new: temp.new});
};
Update Data function call :
updateData(){
// some code
this.setState({...this.state, new: newData});
}

Svelte access a store variable in child component script tag

I have a Svelte & Sapper app where I am using a Svelte writable store to set up a variable with an initial blank string value:
import { writable } from 'svelte/store';
export let dbLeaveYear = writable('');
In my Index.svelte file I am importing this and then working out the value of this variable and setting it (I am doing this within the onMount function of ```Index.svelte if this is relevant):
<script>
import {dbLeaveYear} from "../stores/store.js"
function getCurrentLeaveYear() {
const today = new Date();
const currYear = today.getFullYear();
const twoDigitYear = currYear.toString().slice(-2);
const cutoffDate = `${twoDigitYear}-04-01`
const result = compareAsc(today, new Date(cutoffDate));
if (result === -1) {
$dbLeaveYear = `${parseInt(twoDigitYear, 10) - 1}${twoDigitYear}`;
} else {
$dbLeaveYear = `${twoDigitYear}${parseInt(twoDigitYear, 10) + 1}`;
}
}
onMount(() => {
getCurrentLeaveYear();
});
</script>
I have a child component being rendered in the Index.svelte
<Calendar />
Inside the Calendar child component I am importing the variable and trying to access it to perform a transform on it but I am getting errors that it is still blank - it is seemingly not picking up the assignment from Index.svelte:
<script>
import {dbLeaveYear} from "../stores/store.js"
const calStart = $dbLeaveYear.slice(0, 2)
</script>
However if I use the value in an HTML element in the same Calendar child component with <p>{$dbLeaveYear}</p> it is populated with the value from the calculation in Index.svelte.
How can I access the store variable inside the <script> tag of the child component? Is this even possible? I've tried assiging in onMount, I've tried assigning in a function - nothing seems to work and it always says that $dbLeaveYear is a blank string.
I need the value to be dynamic as the leave year value can change.
Before digging deeper into your problem, let me say that you shouldn't mutate the store variable directly, but use the provided set or update method. This avoids hard-to-debug bugs:
if (result === -1) {
dbLeaveYear.set(() => `${parseInt(twoDigitYear, 10) - 1}${twoDigitYear}`);
} else {
dbLeaveYear.set(`${twoDigitYear}${parseInt(twoDigitYear, 10) + 1}`);
}
With that out of the way, the problem seems to be that your auto-subscribe to the store is not ideal for your use case. You need to use the subscribe property for that:
<script>
import { dbLeaveYear } from "../stores/store.js"
import { onDestroy, onMount } from "svelte"
let yearValue;
// Needed to avoid memory leaks
let unsubscribe
onMount(() => {
unsubscribe = dbLeaveYear.subscribe(value => yearValue = value.slice(0, 2));
})
onDestroy(unsubscribe);
</script>
Another thing that could cause your problem is a race condition. So the update from the parent component is not finished when the child renders. Then you would need to add a sanity check in the rendering child component.
The answer here is a combination of Sapper preload and the ability to export a function from a store.
in store.js export the writable store for the variable you want and also a function that will work out the value and set the writable store:
export let dbLeaveYear = writable('');
export function getCurrentLeaveYear() {
const today = new Date();
const currYear = today.getFullYear();
const twoDigitYear = currYear.toString().slice(-2);
const cutoffDate = `${twoDigitYear}-04-01`
const result = compareAsc(today, new Date(cutoffDate));
if (result === -1) {
dbLeaveYear.set(`${parseInt(twoDigitYear, 10) - 1}${twoDigitYear}`);
} else {
dbLeaveYear.set(`${twoDigitYear}${parseInt(twoDigitYear, 10) + 1}`);
}
}
In the top-level .svelte file, use Sapper's preload() function inside a "module" script tag to call the function that will work out the value and set the writable store:
<script context="module">
import {getCurrentLeaveYear} from '../stores/store'
export async function preload() {
getCurrentLeaveYear();
}
</script>
And then in the component .svelte file, you can import the store variable and because it has been preloaded it will be available in the <script> tag:
<script>
import {dbLeaveYear} from '../stores/store'
$: startDate = `20${$dbLeaveYear.slice(0, 2)}`
$: endDate = `20${$dbLeaveYear.slice(-2)}`
</script>

Reference to component

Using knockout.js in node, how can I get a reference to a child VM component, which was invoked from a template?
Illustration
I have a Question Model, VM, containining a custom Resource component, with it's respective Model and VM. The Resource VM registers a custom component and receives a Resource Model object as a parameter, which was constructed by the parent Question Model. This constructed resource is passed as a parameter with the template:
QuestionModel.js
this = new QuestionModel(...);
this.resource = new ResourceModel(some data);
question-template.html
<div data-bind="foreach: { data: questions, as: 'question' }">
<!-- question related -->
<resource params="resource: question.resource"></resource>
</div>
ResourceVM.js
define(function(require, exports, module) {
var ko = require('knockout');
var ResourceViewModel = function ResourceViewModel(params) {
this.resource = params.resource;
this.somethingSpecific = function() {
return 'some value manipulate from this model';
}
}
ko.components.register('resource', {
viewModel: {
createViewModel: function(params, componentInfo) {
return new ResourceViewModel(params);
}
},
template: {
require: 'text!/resource-template.html'
}
});
return ResourceViewModel;
});
I want to be able to call functions of the Resource VM (like question.resourceVM.somethingSpecific()).
What is a proper way of getting a reference to a component child?
The only solution I can think of is to pass the parent object with the parameters and extend it from child, which is obviously bad.
Your QuestionModel already has access to this.resource, so the way forward might be by doing it through the data models, instead of through the view models. Having somethingSpecific() as an attribute on either QuestionModel or ResourceModel instead of ResourceViewModel would solve the problem nicely.
I would argue that manipulating data is the responsibility of the entity that holds it; the job of the ResourceViewModel is only to provide glue between the data model and the DOM.
var QuestionModel = function QuestionModel() {
this.somethingSpecific = function somethingSpecific() {
this.resource.doStuff();
};
};
this = new QuestionModel();
this.resource = new ResourceModel(some data);
You could then give your resource component access to the question instead of the child resource:
var ResourceViewModel = function ResourceViewModel(params) {
this.question = params.question;
this.resource = this.question.resource;
}

Object.defineProperty on any property [duplicate]

I am aware of how to create getters and setters for properties whose names one already knows, by doing something like this:
// A trivial example:
function MyObject(val){
this.count = 0;
this.value = val;
}
MyObject.prototype = {
get value(){
return this.count < 2 ? "Go away" : this._value;
},
set value(val){
this._value = val + (++this.count);
}
};
var a = new MyObject('foo');
alert(a.value); // --> "Go away"
a.value = 'bar';
alert(a.value); // --> "bar2"
Now, my question is, is it possible to define sort of catch-all getters and setters like these? I.e., create getters and setters for any property name which isn't already defined.
The concept is possible in PHP using the __get() and __set() magic methods (see the PHP documentation for information on these), so I'm really asking is there a JavaScript equivalent to these?
Needless to say, I'd ideally like a solution that is cross-browser compatible.
This changed as of the ES2015 (aka "ES6") specification: JavaScript now has proxies. Proxies let you create objects that are true proxies for (facades on) other objects. Here's a simple example that turns any property values that are strings to all caps on retrieval, and returns "missing" instead of undefined for a property that doesn't exist:
"use strict";
if (typeof Proxy == "undefined") {
throw new Error("This browser doesn't support Proxy");
}
let original = {
example: "value",
};
let proxy = new Proxy(original, {
get(target, name, receiver) {
if (Reflect.has(target, name)) {
let rv = Reflect.get(target, name, receiver);
if (typeof rv === "string") {
rv = rv.toUpperCase();
}
return rv;
}
return "missing";
}
});
console.log(`original.example = ${original.example}`); // "original.example = value"
console.log(`proxy.example = ${proxy.example}`); // "proxy.example = VALUE"
console.log(`proxy.unknown = ${proxy.unknown}`); // "proxy.unknown = missing"
original.example = "updated";
console.log(`original.example = ${original.example}`); // "original.example = updated"
console.log(`proxy.example = ${proxy.example}`); // "proxy.example = UPDATED"
Operations you don't override have their default behavior. In the above, all we override is get, but there's a whole list of operations you can hook into.
In the get handler function's arguments list:
target is the object being proxied (original, in our case).
name is (of course) the name of the property being retrieved, which is usually a string but could also be a Symbol.
receiver is the object that should be used as this in the getter function if the property is an accessor rather than a data property. In the normal case this is the proxy or something that inherits from it, but it can be anything since the trap may be triggered by Reflect.get.
This lets you create an object with the catch-all getter and setter feature you want:
"use strict";
if (typeof Proxy == "undefined") {
throw new Error("This browser doesn't support Proxy");
}
let obj = new Proxy({}, {
get(target, name, receiver) {
if (!Reflect.has(target, name)) {
console.log("Getting non-existent property '" + name + "'");
return undefined;
}
return Reflect.get(target, name, receiver);
},
set(target, name, value, receiver) {
if (!Reflect.has(target, name)) {
console.log(`Setting non-existent property '${name}', initial value: ${value}`);
}
return Reflect.set(target, name, value, receiver);
}
});
console.log(`[before] obj.example = ${obj.example}`);
obj.example = "value";
console.log(`[after] obj.example = ${obj.example}`);
The output of the above is:
Getting non-existent property 'example'
[before] obj.example = undefined
Setting non-existent property 'example', initial value: value
[after] obj.example = value
Note how we get the "non-existent" message when we try to retrieve example when it doesn't yet exist, and again when we create it, but not after that.
Answer from 2011 (obsoleted by the above, still relevant to environments limited to ES5 features like Internet Explorer):
No, JavaScript doesn't have a catch-all property feature. The accessor syntax you're using is covered in Section 11.1.5 of the spec, and doesn't offer any wildcard or something like that.
You could, of course, implement a function to do it, but I'm guessing you probably don't want to use f = obj.prop("example"); rather than f = obj.example; and obj.prop("example", value); rather than obj.example = value; (which would be necessary for the function to handle unknown properties).
FWIW, the getter function (I didn't bother with setter logic) would look something like this:
MyObject.prototype.prop = function(propName) {
if (propName in this) {
// This object or its prototype already has this property,
// return the existing value.
return this[propName];
}
// ...Catch-all, deal with undefined property here...
};
But again, I can't imagine you'd really want to do that, because of how it changes how you use the object.
Preface:
T.J. Crowder's answer mentions a Proxy, which will be needed for a catch-all getter/setter for properties which don't exist, as the OP was asking for. Depending on what behavior is actually wanted with dynamic getters/setters, a Proxy may not actually be necessary though; or, potentially, you may want to use a combination of a Proxy with what I'll show you below.
(P.S. I have experimented with Proxy thoroughly in Firefox on Linux recently and have found it to be very capable, but also somewhat confusing/difficult to work with and get right. More importantly, I have also found it to be quite slow (at least in relation to how optimized JavaScript tends to be nowadays) - I'm talking in the realm of deca-multiples slower.)
To implement dynamically created getters and setters specifically, you can use Object.defineProperty() or Object.defineProperties(). This is also quite fast.
The gist is that you can define a getter and/or setter on an object like so:
let obj = {};
let val = 0;
Object.defineProperty(obj, 'prop', { //<- This object is called a "property descriptor".
//Alternatively, use: `get() {}`
get: function() {
return val;
},
//Alternatively, use: `set(newValue) {}`
set: function(newValue) {
val = newValue;
}
});
//Calls the getter function.
console.log(obj.prop);
let copy = obj.prop;
//Etc.
//Calls the setter function.
obj.prop = 10;
++obj.prop;
//Etc.
Several things to note here:
You cannot use the value property in the property descriptor (not shown above) simultaneously with get and/or set; from the docs:
Property descriptors present in objects come in two main flavors: data descriptors and accessor descriptors. A data descriptor is a property that has a value, which may or may not be writable. An accessor descriptor is a property described by a getter-setter pair of functions. A descriptor must be one of these two flavors; it cannot be both.
Thus, you'll note that I created a val property outside of the Object.defineProperty() call/property descriptor. This is standard behavior.
As per the error here, don't set writable to true in the property descriptor if you use get or set.
You might want to consider setting configurable and enumerable, however, depending on what you're after; from the docs:
configurable
true if and only if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object.
Defaults to false.
enumerable
true if and only if this property shows up during enumeration of the properties on the corresponding object.
Defaults to false.
On this note, these may also be of interest:
Object.getOwnPropertyNames(obj): gets all properties of an object, even non-enumerable ones (AFAIK this is the only way to do so!).
Object.getOwnPropertyDescriptor(obj, prop): gets the property descriptor of an object, the object that was passed to Object.defineProperty() above.
obj.propertyIsEnumerable(prop);: for an individual property on a specific object instance, call this function on the object instance to determine whether the specific property is enumerable or not.
The following could be an original approach to this problem:
var obj = {
emptyValue: null,
get: function(prop){
if(typeof this[prop] == "undefined")
return this.emptyValue;
else
return this[prop];
},
set: function(prop,value){
this[prop] = value;
}
}
In order to use it the properties should be passed as strings.
So here is an example of how it works:
//To set a property
obj.set('myProperty','myValue');
//To get a property
var myVar = obj.get('myProperty');
Edit:
An improved, more object-oriented approach based on what I proposed is the following:
function MyObject() {
var emptyValue = null;
var obj = {};
this.get = function(prop){
return (typeof obj[prop] == "undefined") ? emptyValue : obj[prop];
};
this.set = function(prop,value){
obj[prop] = value;
};
}
var newObj = new MyObject();
newObj.set('myProperty','MyValue');
alert(newObj.get('myProperty'));
You can see it working here.
I was looking for something and I figured out on my own.
/*
This function takes an object and converts to a proxy object.
It also takes care of proxying nested objectsa and array.
*/
let getProxy = (original) => {
return new Proxy(original, {
get(target, name, receiver) {
let rv = Reflect.get(target, name, receiver);
return rv;
},
set(target, name, value, receiver) {
// Proxies new objects
if(typeof value === "object"){
value = getProxy(value);
}
return Reflect.set(target, name, value, receiver);
}
})
}
let first = {};
let proxy = getProxy(first);
/*
Here are the tests
*/
proxy.name={} // object
proxy.name.first={} // nested object
proxy.name.first.names=[] // nested array
proxy.name.first.names[0]={first:"vetri"} // nested array with an object
/*
Here are the serialised values
*/
console.log(JSON.stringify(first)) // {"name":{"first":{"names":[{"first":"vetri"}]}}}
console.log(JSON.stringify(proxy)) // {"name":{"first":{"names":[{"first":"vetri"}]}}}
var x={}
var propName = 'value'
var get = Function("return this['" + propName + "']")
var set = Function("newValue", "this['" + propName + "'] = newValue")
var handler = { 'get': get, 'set': set, enumerable: true, configurable: true }
Object.defineProperty(x, propName, handler)
this works for me

phalcon framework -> edit model::find(); results in an foreach loop

As http://docs.phalconphp.com/en/latest/reference/models.html#understanding-records-to-objects says, you can edit the objects once its loaded in the memory.
$settingCategories = SettingCategory::find();
foreach($settingCategories as $settingCategory){
if($settingCategory->type == "2"){
$settingCategory->type = "asd";
$settingCategory->intersection = "asd";
}else{
$settingCategory->type = "blaa";
$settingCategory->intersection = "blaa";
}
$settingCategory->type = "test";
}
$this->view->setVar("settingCategories",$settingCategories);
type is still its default value when I loop through it with volt:
{% for settingCategory in settingCategories %}
<div class="tab-content">
<h4>{{ settingCategory.name }}</h4>
<h4>{{ settingCategory.type }}</h4> --> still (int) integer!?
<h4>{{ settingCategory.intersection }}</h4> --> undefined!?
</div>
{% endfor %}
When you are modifying a variable inside a foreach, you are modifying a "temporary variable". What it means is that since it is only a copy of the real variable, when you change it, the real value inside the array isn't changed. Now, on to what you could do to solve this:
Setters/Getters
I personally prefer this one. If what you want to do is data transformation (I.E. you change the value of a field from one thing to another, and you want to use the new value in your code everywhere), I would use setters and getters. Here is an example:
// This is inside your model
protected $type;
public function getType()
{
if ($this->type === 2) {
return "asd";
} else {
return $this->type;
}
}
public function setType($type)
{
if ($type === 2) {
$this->type = "asd";
} else {
$this->type = 1; // or $type, or anything really :)
}
}
Of course, in your code, you'll have to change $category->type to $category->getType() and $category->setType($type), based on whether you are reading the value or assigning something to it.
The Quick and Dirty Way
Well, if your use case is different, you can use your current code block with a simple modification. Change your foreach to foreach($settingCategories as &$settingCategory). The ampersand makes the variable be passed into the block as a reference (I.E. it is not a copy like your current case). That means changing it will change the real value.

Resources