I am using 'keen-ui' library in my project. Here is special component for select item. I want to handle event from another component and set focus on this, but I don't know how to.
Another components, that have inside <input/> tag can be focused like this.$refs[component name].$el.children[0].children[1].focus, where children[0].children[1] is <input/> element. This is ugly, but if the component doesn't contain input tag, we can not do even this.
Examining the widgets, I see that they contain a div with tabindex="0", which means they can receive focus.
If you have a ref on the component, you should be able to do something like
const focusableEl = this.$refs.uiselect.querySelector('[tabindex="0"]');
focusableEl.dispatchEvent(new Event('focus'));
and the widget will light up. I actually did that from the console to test it out. Interestingly, blur did not work for me.
Related
I am working on a project that combines react-datasheet and Material UI Autocomplete to mimic a dropdown inside an Excel cell. The base requirement consists of allowing the user to type in or choose one of the options when the autocomplete gets focus. That is where my problem resides. Because the autocomplete is nested inside a cell, it does not get focus automatically when the parent cell is selected (for example, using the keyboard arrows).
So far, I tried using refs so that I would be able to call .current.focus() using something like the following:
const inputRef = useRef();
useEffect = (() => {
if (selected) {
inputRef.current.focus();
}
}, [selected]);
where selected is a boolean prop that I'm passing from the parent cell to the autocomplete. In other words, I'm trying to somehow make it get focus programatically when selected is true. If you have any tips or ideas to get this to work, or another potential approach I could investigate, I would appreciate it.
EDIT: Here's the component tree as shown in the React Dev Tools. Upon inspecting the autocomplete, it does not expose a focus() method. I see there are inputs down the tree but I am not clear on how I can call focus on them and if that would cause the autocomplete to get focus.
The parent (actually, ancestor) cell component. Here's where I have the selected prop.
The Material UI Autocomplete.
Inputs
#newdev I ran into the same issue and #Dekel's answer here helped solve the mystery: react material ui autocomplete element focus onclick.
TLDR: You need to add the ref to the TextField element in Autocomplete's renderInput prop.
I have two different components in my React application.One component to display pop up, and other for text search field.
There is no relation(parent-child)between them.
My question is when user clicks pop up message(component), be focused text field in another component.
How can I handle this situation without using document.getElementById?
only using a react a specific way like reactDOM with ref.
Is it possible to handle like that?
Thanks
Find the common parent component, and write a function which updates a state with ref of the element to be focused. Pass down that function as props to the second component.
And use <input ref={r => this.props.func(r)
Now on click of first component you can access this parent state.
I want to have a base-input component, then a number-input component that extends that, and a currency-input component that extends that.
By extend I was hoping to just have the 'child' component (in inheritence terms) use the parent component in its template since that seems to be the 'Vue way'.
But I want to be able to automatically support events etc without having to manually add handles for #click, #blur, #keyup, etc (or any other events that get added later)
Ideally I would like to be able to write:
<currency-input #click="clickMe"></currency-input>
and have the currency-input pick up the events of the input that's inside of it.
// baseInput.js
<template>
<input v-on:click="">
</template>
I am also using masked-input in many of the inputs to help with consistent masking. I had a mixin, but that doesn't seem to allow me to change the markup to add the prop rendering. I'm wondering what the recommended way of doing this would be so that I can easily make different types of input components that always have default input functionality.
click.native will listen on a component for a native event to bubble up from an element contained in the component. In your case, it would be
<currency-input #click.native="clickMe"></currency-input>
I was creating a Dropdown component for React. Inside the dropdown, I have a form of radio group buttons.
<DropdownButton />
<DropdownForm />
In the DropdownButton, I have an state to know if it is open or not. Depends on that, DropdownForm it's hidden or not (using display: none).
The use case is: User selects a radio button, click apply and something happen. However, if user selects some radio button, and mouse out the dropdown (without clicking the apply button), the one that is selected should be the one that I get from the store.
Something like:
render: function () {
...
if(store.getSomeParam() != this.state.someParam && !this.props.isOpen){
someParam = store.getSomeParam()
}
Then the radio buttons are like:
<input checked={someParam == "something"} ... />
It doesn't really work. It re-renders but it doesn't change the button that is checked. I also tried with refs:
this.refs.myInput.getDOMNode().checked = true
But still nothing. Is this a correct behaviour?
The only solution I found so far is not using a css hiding class (display: none). So what I do is that the DropdownButton renders the DropdownForm depending on if it's open or not (so if you close it, you are forcing DropdownForm to unmount). Then when opening again, it is taking the values from the store (getInitialState) and it shows the correct radio button selected. But, I am not sure if this is the best solution and if there is any drawback in unmounting the component instead of just css hiding it.
This probably has nothing to do with React at all.
Most browsers don't validate the value of the checked attribute, but merely if it is there or not: http://jsfiddle.net/7jzm7gvw/
Just set the checked attribute to either true or null:
<input checked={someParam == "something" ? true: null} ... />
TL;DR: You must use the componentDidMount lifecycle method, not render, to work with the rendered dom nodes directly.
I was struggling with this as well, and after doing some online research I figured I might as well look into it for myself. Here's what I came up with:
Use the componentDidMount lifecycle method and update whatever you need to in there. Here's a Pen I used to prototype this, and I think it looks okay: http://codepen.io/gholts/pen/GpWzdb
You could drop this in pretty easily to what your'e working on by just putting a componentDidMount method on your object and doing it there. I used document.getElementById but you could definitely use jQuery or whatever else you wanted in there, as once the component has mounted it's available to DOM selectors.
I'm using this now to update 20 radio button groups (so it has to check a prop for three different states and update accordingly) and it loads instantly.
Hope it helps! I used the ES6 class syntax in my Pen, you should check it out if you have some time to refactor :) It's fun.
EDIT: So I figured it out, I'm a dummy. You don't need to do the whole document.getElementById business that I was doing. Just use your this.refs.whichever.getDOMNode().checked = true and it'll work, so long as you do it in componentDidMount. It works there because there is an actual DOM element on the page at that point.
I'm writing an autocomplete custom component as a learning exercise with JSF
2.1.3. The idea (which is probably pretty familiar) is to enter some text into
and input component and present a list box with matching values. The idea is
to have a keyup javascript event on the input which calls jsf.ajax.request()
to update the component. So far I've got a component which I can include like
this:
<mycc:autocomplete id="myauto" searchMethod="#{bean.doSearch}"/>
This renders html like this:
<span id="myauto">
<input type="text" id="myauto_input" name="myauto_input"
onkeyup="com.myco.ajaxRequest(this, event)"/>
<select id="myauto_listbox" name="myauto_listbox">
<option value="1st">First</option>
<option value="2nd">Second</option>
</select>
</span>
The com.myco.ajaxRequest() javascript function (keyup) does this:
jsf.ajax.request(comp, null, {
execute: 'myauto',
render: 'myauto'
});
So because I want to rebuild and rerender the listbox with the suggestions
list, I'm re-rendering the custom component 'myauto'. By specifying execute:
'myauto' the decode() method executes and I can get the input value. By
specifying render: 'myauto' the encode...() methods execute to regenerate
the html.
This is all fine but because I'm rendering the parent of the myauto_input
component I lose input focus every time the keyup event fires.
If I specify something like render: 'myauto_listbox' (I only really want to
rerender the listbox after all) the problem is that the encode...() methods
don't execute, because they're for the custom component as a whole, not just
the listbox. And it would be in one of the encode...() methods that I rebuild
the listbox containing the suggestions.
The component extends UIInput and I generate markup in a separate renderer
(componentFamily = "javax.faces.Input") in the encodeEnd() method (so this
always runs after any supplied converter - not yet implemented). I suppose
that forcing focus from javascript is a horrible hack and to be avoided.
I'm a bit unsure where to go with this, but I suspect that what I'm seeing
indicates that I'm approaching this in the wrong way somehow. If anyone
would be good enough to point me in the right direction I'd greatly appreciate
it.
I've spent some time looking into this and the general issue of losing focus after
an ajax update is fairly common and is described in Jim Driscoll's blog (see
'Keeping Focus').
In the case of my custom component I (think I...) have to update the custom component
itself which is the parent of the input, so I'm going to lose focus as a result of the
ajax update, and that's just the way it is. As such I've looked at what needs to be
done to restore focus, and it seems that in my renderer encode I simply have to
forcibly restore focus to the input, but only when responding to the POST sent from the onkeyup event by jsf.ajax.request. I use jQuery and just calling .focus() isn't
enough because you also have to get the cursor position to the end of any existing
input. This code below seems to work ok:
<script>
jQuery(function($){var cid='#myauto_input';$(cid).focus().focus().click();$(cid).val($(cid).val());});
</script>
(note: .focus().focus().click() required for IE8, just .focus() works on chrome...)
So it looks like the horrible hack has saved the day. I did wonder if there would be
any difference if I used the jQuery ajax routines rather than the jsf ajax library but
I don't suppose it would make any difference.