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

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!

Related

Best practice in assigning a new key/value pair into a nested object

Im using React. and trying to assign an new key value. pair into the object. So first it goes through an if check and if it meets the requirement, I want to add the key value 'author'
if (field.component === 'Author') {
this.props.writer.config.payload.name = 'Jefferson';
console.log(this.props)
}
There are some online articles that tell me to do this way and others that tell me to do Object.assign. Basically though, I just want to add the 'name':'Jefferson' into the object.
See this answer https://stackoverflow.com/a/24943743/1964636
Mutating props in a child component is an anti pattern,
You may want to pass a function as props that can lift state in the child component.
Once you modify the state of it's parent component (assuming the props are part of the parent component's state), it will rerender with updated props.

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

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.

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.

ReactJS: How do I set the default value for input components?

How do I get around the anti-pattern with state from props when using default values for input fields?
When the form is rendered, it should contain some default values. When I set some values and closes the form and then re-opens the form I want the default values to show, not the ones previously entered...
But when I let state inherit values from props, the props are changed forever. I haven't found a way to get around this.
If you look at the default input component, or the inputs from react-bootstrap, or most of the DatePickers and Selects on the internet, you will see that most of them have a value prop, and most of them will have little to none state, at least when it comes to the selected value.
An input is meant to be uncontrolled, meaning that they are better off not having state, and just receiving the value as a prop, as well as a callback they should call when the value changes. It's up to the controller-view above them, to watch these events and change the model. Some times it may be convenient for the inputs to keep the value in the state as well, but they can only do it as long as they respect new value being passed as a prop, because the state persists in rerenders and getInitialState is only called once. See also: ReactJS: Why is passing the component initial state a prop an anti-pattern?
However, because it would be too cumbersome for the controller-view to handle all these value changes, React comes with an utility called ReactLink, which is, very briefly, a way to automatically bind an input to a property in the state of the controller-view. Example: You can bind an input to the property DateOfBirth of the model, which is part of the state of the controller-view.
Now back to your question, you don't actually pass the default value, you pass the value itself, as a prop. The controller-view should decide what it is. What is the value for the DateOfBirth field? None? Ok, I'll pass the default value as the value prop.

Categories