I have a function that builds a matrix-grid style question, where you have multiple questions to the left with radio button responses for each question to the right.
My issue is that, when this function is called more than once (you have more than 1 matrix-grid question), the grid is already pre-populated with the responses from the previous matrix-grid question.
It's worth noting that, in my state the responses from Question1 are unchanged and despite being pre-populated, the state variables for the second question are actually blank until you start clicking
renderFieldlikert(params) {
var count = 0;
let matrixQuestion = params.SubFields.map(function(question, x) {
let questionText = (<li className='left-column'><h4 className='text-left'>{question.Label}</h4></li>);
let radioButtons = params.Choices.map(function(choice, i) {
let val = choice.Score
return(
<li className='animated fadeIn'>
<input onChange={(e) => this.props.handleRadioChange(o.ID, e)} type="radio" name={question.Label} id={++count} key={i} value={val} />
<label htmlFor={count}>{choice.Score}</label>
</li>
)
}.bind(this));
return(
<ul>
{questionText}
{radioButtons}
</ul>
)}.bind(this));
Image 1: User answer's questions
Image 2: Answers from question 1 show up in question 2
Try giving your returned <ul> a unique key so that React can identify that you're trying to render different, unique components. React internally optimizes how it handles the DOM and will re-use HTML elements if it thinks that they are supposed to be the same elements.
An easy way to do this is with Date.now() which will always be unique every time your function returns a new component.
return(
<ul key={Date.now()} >
{questionText}
{radioButtons}
</ul>
)}.bind(this));
However the above won't work if you're calling renderFieldlikert() on every render, causing React to generate a new component every time it renders instead of reusing the same one. key should be unique and generated once before using it in a render method. It would be even better if every param you pass in has some kind of unique identifier and you used that instead.
// Maybe?
return(
<ul key={params.uniqueKey} >
{questionText}
{radioButtons}
</ul>
)}.bind(this));
Related
I've got some JSON that I'm trying to access in React and grab specific pieces of data from, but I only want to pull from the first element in the array (the most recent financial data).
I've got the props on the component, but can't figure out how to get what I need. For instance if I want to access the debtRatios. I tried using map as I've done with the stock component, but it comes back as undefined. Ideally i'd like to have the data from ratio[0] as the props on the ratioInfo component.
<div className="stock-container">
<div className="stock">
{props.stock.map(stock => (
<UserStock key={stock.symbol} stock={stock}/>
))}
</div>
<div className="ratioInfo">
<UserStockRatios ratios={props.ratios}/>
</div>
</div>
Try this
<div className="ratioInfo">
{props.ratios.length > 0 && <UserStockRatios ratios={props.ratios[0]}/>}
</div>
Alternatively if you use babel in your project, this one might work as well:
<div className="ratioInfo">
<UserStockRatios ratios={props.ratios?.[0]}/>
</div>
More infos about Optional Chaining here.
My problem goes like this:
I'm rendering an array of items using "map".
Each rendered item also includes a toggle button component that i created. You can refer this as regular checkbox.
The checkbox value will decided if the rendered item will have a specific css class, with transitions.
Here come's the problem.
On state change, i update the whole list. Therefore, the whole list is being re-rendered. Therefore, i get the relevant item with the relevant boolean value. Despite that, this item isn't modified, it's re-rendered, so the css doesn't change from A to B, it's just getting a new css class instead the previous, so the TRANSITION DOESN'T WORK.
The rendered array:
{this.state.extensions.map((curr,index)=>{
return <div className="single-extension" key={'extension-' + Utils.guid()}>
<div className="toggle-area">
<ToggleButton onChange={(value)=>{
this.handleAssociateExtension(index,value);
}} active={curr.associated}/>
</div>
<div className={ClassNames({'details':true, 'on': curr.associated})}>
<div className="link-text">{curr.link_text}</div>
<div className="description">{curr.description}</div>
<div className="landing-page">{curr.landing_page}</div>
</div>
</div>
})}
The update function:
handleAssociateExtension(index, value) {
let extensions = Utils.cloneObject(this.state.extensions);
if (extensions[index]) {
extensions[index].associated = value;
}
this.setState({extensions: extensions});
}
Thank you in advance! :)
What is the function of the key attribute in the p tag? I inspected the dom, and I expected to see p tags for each element of the taco list as expressed in <p taco-1>, but it's just <p>. Any explanation will be much appreciated.
{this.props.tacos.map( ( taco, i ) => {
return <p key={ `taco-${ i }` }>{ taco }</p>;
})}
It is used by react in a collection of component to see which element is inserted, which element is removed and which element is updated. Without key attribute, it's hard to determine how to update the collection.
For example, see component collection below:
<ul>
<li>England</li>
<li>France</li>
</ul>
and then next state tell react to render:
<ul>
<li>England</li>
<li>Germany</li>
</ul>
There's multiple ways to update the DOM:
Change inner text of second <li>
Remove second <li> and add a new one
Without key, react don't know which one to choose.
You can read more in the docs.
i did not found the answer i was looking for, so that why i'm creating this question. I have a div that shows another one on click but i need to hide it (the div that appears on click) after the user selects one of the options, how can i do that?
When user's click on "#showmenu" the div ".mob" appears, after clicking in one of the ".mob" li's the ".mob" div dissapears.
P.S: Sorry for my bad english.
HTML:
<div id="showmenu"><img src="images/mobile.png" /></div>
<div class="mob" style="display: none;">
<ul>
<a data-scroll href="#home"><li>INÍCIO</li></a>
<a data-scroll href="#servicos"><li>EU FAÇO</li></a>
</ul>
</div>
Code:
$(document).ready(function() {
$('#showmenu').click(function() {
$('.mob').slideToggle("fast");
});
});
I dont have any idea of the bootstrap or jquery plugins you are using but based on what is given, i'd say this should work.
$(document).ready(function() {
$('#showmenu').click(function() {
$('.mob').slideToggle("fast");
$('.mob a').click(function () {
$('.mob').slideToggle("fast");
});
});
});
Point to note there is a performance issue here , i.e code could be optimized better to search for classes or elements within a specific div than the whole document
Should those really be <a> if you don't intend to go anywhere? Can they just be <li>?
After that I think you want to give id's to the <li> that you have and then create a function much like the one you did for $('showmenu').click... that would hide the .mob.
Or if the <li> all get treated the same, maybe give them all the same class and just have one function for the class.
I use routing to load different templates into a ngView. One of the templates has a simple controller which contains an array of contacts. What I'm trying to do here is as simple as by clicking a link (ngclick) call a function and add a new object into the array which I expect will be reflected in my UI.
It's something like this:
$scope.contacts = [{name='', email=''}];
<li ng-repeat="con in contacts">
<input type="text" ng-model="con.name"/>
<input type="email" ng-model="con.email"/>
</li>
<li>
<a href ng-click="addContact()">add</a>
</li>
$scope.addContact = function() {
$scope.contacts.push( {name='', email=''} ); //-- i can use either $scope or this to reference the array and works.
}
So, the UI renders well with the initial value, the addContact function is invoked on click and I see the value is pushed (length = 2) but then the function ends the array seems to be reset to one element (lenght = 1) after angularjs evaluation.
I'm not sure if this is occurring because I use ngView. I mean, I reviewed this example (http://code.angularjs.org/1.0.3/docs/api/ng.directive:ngController) and I don't see much differences of what I'm trying to do here, the diff is that I use routing with ngView.
fiddle: http://jsfiddle.net/fdDph/
Help is much appreciated.
In your Fiddle, you are resetting the array length to 1 in the ng-show:
<span ng-hide="contacts.length = 1">
Do this and it will work:
<span ng-hide="contacts.length == 1">
{name='', email=''} is wrong syntax btw, it should be {name:'', email:''}