Vue.js element reference on attribute - javascript

I have the following code:
<input type="text"
#input="disableField($event.target)"
:disabled="isFieldDisabled(????)"
/>
I want to pass to the isFieldDisabled method the same value which I get in $event.target - the element reference. I cannot find the way how to do this. I know that I could use the :ref but in this case I need to do it as shown above.
This is only the example use case. I know that to disable the field I can do it better but I want to show the problem in simplest way.

This isn't possible the way you're asking for it.
The way that Vue works with VNodes, the element won't exist the first time you try to evaluate disabled: Vue evaluates the properties to determine how the DOM should look and then creates the elements to match. As here:
Note that you can only access the ref after the component is mounted. If you try to access input in a template expression, it will be null on the first render. This is because the element doesn't exist until after the first render!
With async components, the attributes will need to have well-defined values even if there isn't a Component to render yet, let alone well-defined elements to position there.
With fragment components, there won't ever be a single HTML element to interact with, because the component represents multiple top-level HTML elements.
Events don't have to play by the same rules, because you're defining handlers: DOM events will come from one source and apply to one target, and absent components don't emit events. Even then, the syntax gives you access to $event, not to an $el for a direct element reference.
The most straightforward way is to use a ref to get to the object after Vue creates it, subject to the same null-on-first-render ref rules above. If you need to pass a handle into a multipurpose method in the shape of getFoo(argument) your argument may have to be a string or enum key you define, not the element itself.

Related

Vue - access input value inside the input's attribute

Is is possible to access inputs value inside it's definition/attribute?
For example, if you want an input to be green if not empty but you don't want to use Vue.data.
Like this:
<v-text-field background-color="'green' ? <THISVAL> : 'red'"></v-text-field>
Or do I need v-model and variable defined in the Vue.data?
Yes, you do need v-model and variable defined in the Vue.data.
Why? Remember that vue uses virtual DOM. When this template is being processed for the first time, no actual element is present in DOM, to be access via this.
It needs to know what to render into DOM beforehand.
There is component-template-refs to gain references to actual HTML elements, but these references are assigned after the component is mount, and not needed for use cases like this

can I pass a value to a sibling component without saving it as a variable?

I have some bootstrap vue cards with a v-for statement, one of my tags returns a value based on the current iteration of v-for. I want to pass this value to another tag, if I save it as a variable before passing it then all iterations end up sharing the same variables but I don't want that.
<b-card-group v-for="(element, i) in array" :key="index">
<b-card>
<tag #update="updateFunction()" />
<otherTag />
<b-card />
<b-card-group />
I want the variable to be specific to the current iteration so future iterations won't have access to it.
You are basically asking two questions, so I am going to answer them in turn.
The main problem you seem to have is that you do not know how to differentiate between each card in your updateFunction function. The easiest way to make your updateFunction context-aware, is by putting an arrow function that takes one argument, and calls updateFunction with two arguments.
Your update handler would look something like this. You take the index of the card you are trying to update, and the value that was sent from a sibling.
methods: {
handleUpdate(index, val) {
this.$set(this.cards, index, val);
}
}
You then use an arrow function to make the update handler context-aware:
<tag #update="(value) => handleUpdate(index, value)" />
As for the question in the title of your problem description: If you are passing a value as a prop, you have two options. You either put a literal in the prop (e.g. :my-prop="5"), or you put a variable in the prop (e.g. :my-prop="myVariable"). The first one obviously doesn't allow you to change the value, so that is not very useful here. The second one pulls the data directly from the state of the parent component. It is thus not possible to pass data as a prop without it being saved in the parent component.
As shown above, that doesn't mean you can't have different data for different iterations of your v-for though.
There are other methods of sharing data between siblings, which is especially useful in larger applications, by using a vuex store. This will allow you to abstract away data in useful "chunks" (or modules), allowing you to interact with it using getters, mutations and actions. You can find more information using the official documentation.

What is the significance of keys in ReactJS?

I want to understand what happens if I don't use keys in dynamically added components. I removed keys and it renders without any issue and just gave warning messages regarding key usage. Would someone please give some example of what the consequences are if we don't use keys?
Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity:
Example:
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
TL;DR Use unique and constant keys when rendering dynamic children, or expect strange things to happen.
One of the tricky aspects I've found during the few weeks I've been using React.js is to understand the key property you're expected to pass to a component when it's part of an array of children. It's not that you have to specify this property, things will work most of the time apart from getting this warning on the console:
Each child in an array should have a unique "key" prop. Check the render method of undefined.
By reading the linked documentation it can be easy to not see the implications of this affirmation:
When React reconciles the keyed children, it will ensure that any child with key will be reordered (instead of clobbered) or destroyed (instead of reused).
At first it looked to me it was all about performance but, as Paul O’Shannessy pointed, it's actually about identity.
The key here is to understand not everything in the DOM has a representation in React "Virtual DOM" and, because direct manipulations of the DOM (like a user changing an value or a jQuery plugin listening an element) are unnoticed by React, not using unique and constant keys will end up with React recreating the DOM node of a component when the key is not constant (and losing any untracked state in the node) or reusing a DOM node to render another component when the key is not unique (and tying its state to this other component).
Here you have a live demo showing how awful the results are:
http://jsfiddle.net/frosas/S4Dju/
Just add an item, change it, add more items and see what happens.
Also see
Source
Another useful usage of React keys other than creating dynamic elements is reseting elements when their keys change, for example in a project I had an <input/> element of type file and I wanted the element to be initialized to its initial value (no file chosen) each time the component renders, so I did the following:
Parent constructor:
this.state = {
fileInputKey: Date.now()
// other properties
};
The state object also had other properties, I just added this one for the sake of this example
Each time I wanted the input element in the child component be reset I did:
this.setState({fileInputKey: Date.now()});
Parent render:
<Child fileInputKey={this.state.fileInputKey}/>
Child render:
<input key={this.props.fileInputKey} type="file" onChange={this.onSelectFile}/>
Also see this example from React blog:
https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key

Best practices for the input helper in new Ember components

I'm currently learning about Ember's new data-down, actions-up paradigm for components. As discussed here, however, sometimes I want to allow the child component to modify the property explicitly. This is where the mut helper comes in: it creates a wrapper for the passed in value, containing a (readonly?) value and a function to update it. The example on that page is for a simple button which increments a counter.
How does this concept work if I'm using the input helper inside a component? For example, let's say I'm building a form which consists of a bunch of special form components:
// templates/index.hbs
<form>
{{form-control value=(mut model.firstValue)}}
{{form-control value=(mut model.secondValue)}}
</form>
If the form-control component just has the task of wrapping the input control, how do we use the passed-in mut object correctly? Is it something like?
// templates/components/form-control.hbs
{{input type="text" value=attrs.value.value input=attrs.value.update}}
My thinking here: the value of the input element is set to the value of the mut object, and whenever the input value changes (HTML5 input event) the update method of the mut object is called to set the model property to the new value. It seems there's something wrong with my thinking though, because this doesn't work. What is the "standard" way of doing this now? I'm using Ember 1.13.8.
In classic components (as opposed to glimmer components), all bindings are mutable, so it is not generally necessary to use the mut helper. The following should work fine:
// templates/index.hbs
<form>
{{form-control value=model.firstValue}}
{{form-control value=model.secondValue}}
</form>
// templates/components/form-control.hbs
{{input type="text" value=value}}
The intended use of both the mut helper and of attrs is for glimmer components, also called angle bracket components, which are currently not released in Ember.js' stable releases.

Javascript selector engines and built in functions

I have found the following tutorial on creating a selector engine..
http://blog.insicdesigns.com/2010/04/creating-your-own-selector-engine/
In javascript we have functions like
getElementById()
getElementsByTageName()
getElementsByName()
etc,.....But for the same functionality,in their selector engine,they are doing checks like
this.nodes[i].tagName == nm.toUpperCase()
instead of getElementsByTagName.What is the advantage of this approach?...
Also what is the usage of assigning all nodes to a vairiable using
e.getElementsByTagName('*');
There is an inconsistency when you get the tagName property of elements. Some browsers return uppercase and others lowercase. To normalize the output of the value, you have to do one or the other before continuing further operation.
As for e.getElementsByTagName('*');, i recently answered a question where the OP wants to find ALL elements containing an attribute name which has a prefix mce_. The only way to get such elements is to get all elements in the DOM, and inspect their attribute names.
There is also a good application of this getElementsByTagName('*') and that is determining the direct child of an element. For instance, in a very deep DOM. If I were to find certain parent elements based on an attribute and get it's children, normally you would do a recursive search from body downwards to find the parent. This would take a lot of recursive operations. Afterwards, you determine their children.
Another way to do it is to get all tags, determine their parent node, and if they have the parent with the attribute, they are the direct child. This method requires no recursion, only getElementsByTagName('*') and a loop through the nodeList that was returned.
this.nodes[i].tagName == nm.toUpperCase() is part of a method to filter the list of nodes by tag name.... so nothing to do with 'getting elements by their tag name'
the last point is not a real question.. you want to know reasons for "why would you select all nodes"? well you are writing a sector engine....
The following line
this.nodes[i].tagName == nm.toUpperCase()
Is within the function ofTag. It's filtering a set of nodes looking for nodes with the given name.
The next line
e.getElementsByTagName('*');
Retrieves all the children/descendants under a node so you can later filter it like the following
new DOMNodes(Selector.getAll(document)).ofTag('p').hasClass('note');

Categories

Resources