VueJS custom v-model without value property - this shouldn't work? - javascript

Based on my understanding of using v-model on a custom component (docs link below) the custom component should either:
Have a property on the data object of "value" since by default v-model is really 'v-bind:value="valuePassed"'
Have a "model" property on the component instance to specify which property to use.
Therefore, why does this fiddle work?
https://jsfiddle.net/mpctwfaq/2/
EDIT: This fiddle seems to work on Firefox but not Chrome at the moment...
parent:
<custom-select v-bind:options="formOptions" v-model="formOptionsVModel">
child:
this.$emit("input", this.customArraySelectedOptions)
Specifically, I emit the input event to the parent component with the name of a custom property "customArraySelectedOptions". However, I AM able to update the child component from the parent method by resetting the parent's "formOptionsVModel" property.
I would think based on the documentation the "downward" update should fail since the child's component property is not "value" and does not define a specific property using "model".
Docs: https://v2.vuejs.org/v2/guide/components-custom-events.html#Customizing-Component-v-model

v-model is syntax sugar for =>
:value="modelValue" #input="modelValue = $event.target.value"
And hence your variable is being updated.

Related

React.js Ref Usage

I'm trying to understand usage of the Ref in React. I saw an example in the Ant Design documentation. https://3x.ant.design/components/tag/#components-tag-demo-control
There is a one line code that I couldn't get how it works.
saveInputRef = input => (this.input = input);
And usage as follows:
<Input ref={this.saveInputRef} ...
But in the React documentation, it is said that you create a ref using React.createRef() method.
https://reactjs.org/docs/refs-and-the-dom.html#adding-a-ref-to-a-dom-element
Is it an alternative way of using it? Why there is no React.createRef() method?
As far as I know there are 2 different kind of Refs, but they are commonly used together.
A. There is "Ref" created by "createRef" (or "useRef" when using hooks);
This stores a value in the "current" property of the Ref. This value won't cause rerenders and is kept after rerenders.
B. And there is ref as a property of build-in components. This property is used to access the domnode.
Usually ref (B) is stored in a Ref (A)
You can, however, store whatever you'd like in Ref (A).
And you don't need necessarily need to store a node gotten from ref (B) in a Ref (A), you can access it directly as well, that what this piece of code does:
<div ref={node => doSomething(node)}/>
Or simply
<div ref={doSomething}/>
This is called a "callback Ref":
Callback Refs
React also supports another way to set refs called “callback refs”, which gives more fine-grain control over when refs are set and unset.
Instead of passing a ref attribute created by createRef(), you pass a function. The function receives the React component instance or HTML DOM element as its argument, which can be stored and accessed elsewhere.
https://reactjs.org/docs/refs-and-the-dom.html#callback-refs
EDIT:
more about Ref (A) when using hooks.
Essentially, useRef is like a “box” that can hold a mutable value in its .current property.
You might be familiar with refs primarily as a way to access the DOM. If you pass a ref object to React with , React will set its .current property to the corresponding DOM node whenever that node changes.
However, useRef() is useful for more than the ref attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.
This works because useRef() creates a plain JavaScript object. The only difference between useRef() and creating a {current: ...} object yourself is that useRef will give you the same ref object on every render.
Keep in mind that useRef doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render. If you want to run some code when React attaches or detaches a ref to a DOM node, you may want to use a callback ref instead.
https://reactjs.org/docs/hooks-reference.html#useref

VueJS: How can I access prop defaults from outside the component?

Basically, I'm looking to access prop defaults (value and type) from outside the component.
As background, I'm trying to create a form automagically based on the component selected. And I'd like the form to use the components default prop values, but I can't figure out how to access these from the vue instance of the prop (or through $props either). A workaround for me is to use the current value from $props, but this doesn't let me see the type value declared there. Thanks!

Where to store the state to make React components more reusable

I have an autocomplete component which has following props:
value (display text),
onChange (fired on every keystroke)
onSelect(fired when user picks something from the list of
suggestions, passes selected object + display text of selected object - the same as value)
state:
- suggestionsList (I've decided it's a state as it's something internal to the component).
On one of the views parent of this component doesn't care about the value after each keystroke. It just cares about the selected item passed by onSelect handler. So in this scenario value & onChange props are not needed. value could become an internal state of the autocomplete component.
But on one of the other views parent would like to also know about each keystrokes. This means the parent would need to hold the value in his state and also pass it as props. onChange props would be also needed to notify parent to change its state.
How to construct the autocomplete component so it handles both scenarios? Which properties should be props and which state?
Any suggestions appreciated.
In the second case, if the parent needs to know about the current value, it doesn't need to hold the variable, so I guess that if you pass the current value (from an internal state variable) as a parameter to the onChange prop function, the parent will notice the change and update accordingly.
Another way to do it is to use the value property and a internal state variable. What I mean is: if the parent wishes to control the value it will have an state entry for it and will be responsible for updating it, in other case the value property must not be provided because it would end as a constant. Your component will use this property as the current value every time its provided, and the parent should use onChange to update the va;ue that it holds.
You can check the source code of the auto complete component in material-ui.

Angular 2 - pass an object field by reference. Reusable way to edit objects

I am creating reusable table component which will enable editing of objects fields to prepare them for sending to the API.
Having an object:
person: {
name: "John"
job: {
type: "IT"
title: "Software Engineer"
}
}
I would like to pass the object nested field to a component and edit. F.e:
<edit-field [field]="person.job.title"></edit-field>
Which results in an input field that edits exactly the title field in original object. The problem is that person.job.title is a string, not and object or array so it's not passed by reference.
I had 2 ideas haw the problem could be solved:
1) pass "person.job.title" as a string:
<edit-field [field]="'person.job.title'"></edit-field>
or
<edit-field field="person.job.title"></edit-field>
And in component class do split by a ".":
let fields = this.field.split('.');
and then do a while loop to access the field by reference.
We could also do 2 inputs:
<edit-field-component [fieldRef]="person.job" [field]="'title'"></edit-field-component>
and then inside component do this.fieldRef[this.field]
I am wondering if there is any other, more clean, way to achieve that.
Basically, you want to accomplish two-way binding - i.e. changes to the object value: eg person.job.title updates your new edit component, but also changes made from your edit component also get reflected back to the object value.
In Angular, that means you have to bind both ways:
<edit-field [field]="person.job.title" (change)="person.job.title=$event"></edit-field>
where your edit-field component has an #Output property that emits the changed value whenever someone types into it. The value emitted from the #Output property will be in the variable $event and you simply want to assign that back to the property that you want to update.
So, your EditFieldComponent can look something like:
#Component({
.....
template: `
<input (input)="change.emit($event.target.value)" .... />
`
})
export class EditFieldComponent {
change = new EventEmitter();
}
The above means that whenever an input event triggers on your input field, the component's change output property will emit the new value of the input field.
===========
If you understand everything above, then Angular provides a little shortcut for this exact scenario. If the output property of your component is named a specific way, you can simplify how you write the two way binding.
So, if your input property is field, and you name your output property fieldChange you can make use of some fancy syntax to cut down how much you have to type.
i.e.
<edit-field [field]="person.job.title" (fieldChange)="person.job.title=$event"></edit-field>
is equivalent to:
<edit-field [(field)]="person.job.title"></edit-field>
[field]="person.job.title" is one-way binding (changes of person.job.title are propagated to field but not the other way round)
[(field)]="person.job.title" would achieve two-way binding (changes made by fieldChange method are also propagated back to person.job.title)
If you want to reffer your object or property of your object to your component, you need to create an #Output property with type eventEmitter.
#Input('field') field: any;
#Output() fieldChange = new EventEmitter();
Be carefull to name your output property with "Change" suffix word. It will detect automatically change from your object and notify to your main object.
Javascript just like Java is passed by value, they have never offered passed by reference. So in your case, your best option is to pass your person object directly. Even though it will be copied inside your function, the copy still refers to the same object, so changing a field in the copy will also change the corresponding field in the original.

What is `[()]` syntax used for in angular2?

I know we use
() for detecting event like
<div (click)="doSomething()">
or
<div (blur)="doSomethingElse()">
and {{}} for converting variable to string in template like
<div>{{a_variable_i_want_to_show}}</div>
but what do we use [()] for besides two way binding in ng-model?
Is there a generic usage?
It is two-way binding. Checkout their cheatsheet:
Sets up two-way data binding. Equivalent to: <my-cmp [title]="name" (titleChange)="name=$event">
When used with NgModel, [()] sets up two-way databinding between a component property and a DOM form element. Any change we make to the component property is automatically propagated to the DOM, and any change we make to the form element (i.e., the DOM) is automatically propagated to the component property.
When used with a component, [()] sets up two-way databinding between a parent component property and a child component property. Any change we make to the parent component property is automatically propagated to the DOM. However, any change we make to the child component property is not automatically propagated to the parent – we must use emit(). So it's a little different than NgModel.
The child component must define an input property and an output property, which is an EventEmitter. If the input property is named x, the output property must be named xChange. The child component must explicitly emit any change to x by calling xChange.emit(newValue).
The reason for the naming requirements is because [(childProp)]="parentProp" is a shorthand for [childProp]="parentProp" (childPropChange)="parentProp=$event".
If you need to execute some logic in the parent when a new value is emitted from the child, you'll want to use the expanded form: [childProp]="parentProp" (childPropChange)="doSomething($event)".

Categories