I have a set of components being rendered from a .map() function in my React application.
I have a function that fires on element's onClick which works great. However, I also need to fire this function automatically on a specific element when the page loads.
Here's a rather rudimentary example: https://codesandbox.io/s/ecstatic-cartwright-ve84yt.
So in the example, I have an array of 5 names, when you click the card, the field at the bottom displays the name of the selected card.
What I'm trying is to pre-select (Without using setState's initial value) one of the cards.
If the selectedName is not initialize, select first name in the list.
Selected Name: {this.state.selectedName || names[0]}
https://codesandbox.io/s/little-hill-wv4200
If you want to preselect. You have to use componentDidMount lifecycle react method. It will be fired after your component will be rendered.
componentDidMount() {
this.setState({
selectedName: names[1]
});
}
Related
I am trying to target a specific node in my react reusable component and perform an operation on it. But I want to be able to do same thing several times independently because I will be returning this my reusable component several times on the same page on my App.js. How do I target that div node uniquely?
Here is my situation:
I created a react class component (I am not using function component for this project). This component contains two divs and a button. The first div is a red box. Under it is the second div which is empty with the class "result". There is also a button. When I click this button, the package Html2Canvas will convert the first div into an image and append it to the second div.
Now from the Html2Canvas documentation, they only specified how to append the generated canvas to the body of the DOM:
html2canvas(document.querySelector("#capture")).then(canvas => {
document.body.appendChild(canvas)
});
Since I needed to append to that empty second div, I did:
html2canvas(document.querySelector("#capture")).then(canvas => {
document.queryselector('.result').appendChild(canvas)
});
This would have been fine if I am just using this component once on a page, but in my App.js, I am actually returning this my component multiple times, so what now happens is that each time I click that button, it targets only the first instance of the empty whereas what I need is that each occurrence of my component should behave like the first one independently.
Yes I have tried using CreateRef() to target the current occurrence oof the empty dive but it does not work. It sees the ref as undefined when I call it inside the Html2Caanvas function. But outside of it, it is defined. Ok I tried creating the ref inside, still gave an error of undefined.
I understand that this whole thing I have written may be somewhat vague, so here is a CodeSandBox example of what I want.
When you open it and click on the first "Finish" button, you will see that the red box gets converted to an image, and the image is added under the red box, that is, it is appended to the div with class "result". But when you click on the second "Finish" button, instead of the generated image of the blue box coming under the blue box div, it goes under or beside the previous image. The expected behavior is for it to appear under the blue box. And if I replicate that component "ReUsable" as many times as I want in the App.js, the same behavior is expected. Independence.
I know this is a lot. I look forward to and appreciate your solutions.
First, the ref approach was great (the one you commented out), only that you were referencing the containerRef and not the screenshotRef.
the main issue came from the callback function passed to html2canvas, even though you called bind on handleFinish, binding "this" context to the current class context, the execution context of "this" in the callback is undefined because you used a regular function and regular function always refers to the context of the function being called(html2canvas).
arrow functions on the other hand treat the "this" keyword differently. They don't define their own context.
kindly update your handleFinish method to this
handleFinish(event) {
html2canvas(this.containerRef.current, 1).then((canvas) =>{
this.screenshotRef.current.append(canvas);
// document.querySelector(".result").append(canvas);
});
}
There is an UI I have created using React. There are two text fields to enter value, after entering and saving those values will be populated in a table below the two fields(we are using antd for designing).
However when I click a single record in the table and click edit in that particular record data from that record will be populated to the above mentioned text fields. When this happens I want my app to scroll up and show those two text fields which are ready to be edited.
But currently it stays at the same position after clicked edit, without scrolling up and showing two text fields. Here's an image descripting my experience
Check this answer to find how to control srollTop: https://stackoverflow.com/a/55184755/2360631
But I don't think it's a good idea, maybe you can consider to freeze the edit area otherwise when you finish edit you may need to scroll back again...
Basically you want to set focus to some component after a re-render.
To refer to a particular component, use react refs
make a react ref of whatever you want to set focus to and assign it as a ref prop
constructor() {
super();
this.foo = React.createRef();
}
componentDidUpdate() {
this.foo.current.focus();
}
<Bar ref={this.foo}> .... </Bar>
foo is the name of ref
Bar is the component you want to set focus to
in your case it can be a parent of both input fields or any one of the input fields
I have a good history playing with react. But today I faced a very strange issue.
I have a hamburger which receives a list of values and the one of the values is selected which I send from the parent through this.refs.child1.setValues(). this setValues function calls setState and that one value is selected through className parameter in react.
So in the first step I select first value among 20 values.
the react tab shows this about the first li element:
className="{something} +class1"
rest all elements have:
className="{something}"
which is fine. ('class1' is the class which is added dynamically on setstate) and the dom shows first value selected and the rest unselected.
now problem is in the second step as I select another value say 3rd one, so first value should get deselected and 3rd should be selected and the expected react values for 3rd should be
className="{something} + class1" and for the rest its showing className="{something}"
which is working fine in the react tab BUT in the elements tab both the li elements are getting selected as they both have class1 but class1 should be only with the 3rd element not with the first one (which was previously selected)
Since React works by using the Virtual DOM, it only makes changes in the DOM to elements it detects a change to. So, since you're never actually removing a class from the first element, it never does a rerender of it, it only rerenders the third one because that's the only one you actually changed.
You need to do something like this:
removeClass() {
let allLinks = document.querySelectorAll('.something');
allLinks.map((link) => link.classList.remove('class1'));
//and here just call the function to add the class to the right
//element.
}
All the examples I have found that keep local state can't provide an initial value for the input. In my case a parent component retrieves field from a server and passes these to my input form where the fields shall be editable. But I don't want to pass each change back up the hierarchy if I can avoid it, rather only when the form is submitted (either via button or by pressing enter)
Update: the usage is as follows. Imagine a todo list. The top level holds the list and the detail component. When I click at the list the detail should update to show the selected todo text. That text should be editable.
So as far the the detail component goes the initial state of the input is the text from the list that gets passed down in props. It needs to change when a different todo in the list is selected. On the other hand I should be able to edit it and when submit triggered that todo text should be passed back up via a callback prop.
So I have to keep local state to collect the input, but I want that state to be initialized with the existing todo text from the list. If I use the Facebook example of an uncontrolled form, I find the edited text remains displayed when I switch to a different todo in the list. Maybe I'm doing it wrong or is it a conceptual problem? Using controlled input initializing the state in the constructor doesn't work either because the constructor only gets called once (not on each re-render)!
I solved the problem by using the lifecycle method componentWillReceiveProps(nextprops) where I can set the state to the new props. This method gets called each time a re-render becomes necessary - in my case because the parent changes the childs props.
See https://facebook.github.io/react/docs/react-component.html#componentwillreceiveprops
You can set the initial state based on the property passed in from the parent, then edit that state in the component before submitting with the form submission
Hi I want to hide an adf component automatically.I have a selectOneChoice that contain some number (from 1 to 12).
Example when I select 2, it show's two field automatically without clicking any button..
i used this function to hide a declared componenet but just when i click a button..
function enableField(actionEvent) {
var nameInputText = actionEvent.getSource().findComponent("soc1");
nameInputText.setProperty("visible", true);
actionEvent.cancel();
}
i set the componement "soc1" visible = true than through the javascript function i change it..
SO the probleme here is how to read the number from the selectonechoise and how to set the component visible directly without clicking any button.
Actually Rendered won't do what you want. You want to use Visible property instead. Rendered causes the actual markup for the component not to be rendered on the page, so a Partial Refresh will not cause it to appear. Rendered is reserved, usually, to hide items that are secure. We set rendered property to false on the item(s), but then refresh the parent containing component - usually a layout manager - then it works. So either refresh the layout manager that contains the item or use Visible. I demonstrated this exact use case last week in class and it works as described.
Basicaly, you don't need javascript solution or any programming to achieve this.
You should set attributes rendered(this way component won't be rendered at the page at all) and partialTriggers that points to selectOneChoice component for components you want to show or hide. Also you have to set autoSubmit="true" for your selectOneChoice component.
<af:selectOneChoice id="soc1" autoSubmit="true" .../>
<af:panelGroupLayout id="plg1" partialTriggers="soc1">
<af:outputText id="ot1" rendered="#{bindings.lov.inputValue le 1}" inputValue="text1"/>
</af:panelGroupLayout>
Note: its not working code, just a sample
It will work following way, on valueChange event at selectOneChoice component value is submitted and partialRefresh fires for components that have it in partialTriggers specified. And rendered attribute will either render or remove component depending on it's EL expression. Components that should be managed wrapped into another component to make sure PPR reach it when they ain't rendered.