I am facing an intriguing bug in React.
I have this component:
'use strict';
import SummaryStore from '../stores/SummaryStore';
import React from 'react';
export default class ChangeSummaryForm extends React.Component {
constructor() {
// store initialisation
SummaryStore.register();
var vRating = SummaryStore.getBookForSummaryPrint().summaryRating;
var vStarClassName = this.getRatingClasses(vRating);
this.state = {
sStarClassName: vStarClassName,
sCurrentBookToShow: SummaryStore.getBookForSummaryPrint()
};
this.thereIsASummaryToShow = this.thereIsASummaryToShow.bind(this);
}
getRatingClasses(pRating) {
var vI, vStarClassName = [];
for(vI = 0; vI < 4; vI++) {
if(pRating > 0) {
vStarClassName.push("glyphicon glyphicon-star");
pRating--;
} else {
vStarClassName.push("glyphicon glyphicon-star-empty");
}
}
return vStarClassName;
}
componentDidMount() {
SummaryStore.addChangeListener(this.thereIsASummaryToShow);
}
componentWillUnmount() {
SummaryStore.removeChangeListener(this.thereIsASummaryToShow);
}
thereIsASummaryToShow() {
this.setState({sCurrentBookToShow: SummaryStore.getBookForSummaryPrint(),
sStarClassName: this.getRatingClasses(SummaryStore.getBookForSummaryPrint().rating)
});
$("#summaryModal").modal('show');
}
render() {
return (<div className="modal fade" id="summaryModal">
<form>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button type="button" className="close" data-dismiss="modal" ariaLabel="Close"><span ariaHidden="true">× </span> </button>
<div style={{color: 'black'}}>
{this.state.sStarClassName.map(function(pCurrentClassName) { return (<span className={pCurrentClassName}></span>
);
})}
<h4 className="modal-title">Summary of {this.state.sCurrentBookToShow.title}</h4>
</div>
</div>
<div className="modal-body">
<div className="form-group">
<textarea className="form-control" rows="22" ref="summaryContent" >{this.state.sCurrentBookToShow.summary}</textarea>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal" >Close</button>
<input type="submit" className="btn btn-primary" value="Save"/>
</div>
</div>
</div>
</form>
</div>
);
}
}
As you might notice, it's a controller-view listening at a store which is registered to my AppDispatcher.
The steps above are correctly performed. i.e, when the particular action is triggerd, my component is correctly rendered with the variables {this.state.sCurrentBookToShow.title} and this.state.sCurrentBookToShow.title up-to-date.
The problem comes from this part:
<textarea className="form-control" rows="22" ref="summaryContent" >
{this.state.sCurrentBookToShow.summary}
</textarea>
The string is not printed in the textarea.
I tried this to debug:
render() {
var summary = "this is a summary";
return (// .. shortened for brevity
<textarea className="form-control" rows="22" ref="summaryContent">
{summary}
</textarea> ..);
}
the summary string printed correctly inside the mutable textearea.
Note that my browser says:
Warning: Use the defaultValue or value props instead of setting
children on <textarea>.
But I will fix this later since I think it doesn't have an effect on the current problem.
EDIT:
I took your remarks (so far) in consideration, so I updated my code like so:
<h4 className="modal-title">Summary of {this.state.sCurrentBookToShow.summary}</h4>
</div>
</div>
<div className="modal-body">
<div className="form-group">
{this.state.sCurrentBookToShow.summary}
<textarea className="form-control" rows="22" ref="summaryContent" defaultValue={this.state.sCurrentBookToShow.summary}></textarea>
</div>
I replaced this.state.sCurrentBookToShow.title by .summary to make
sure the ladder is not empty.
I put the summary into a defaultValue prop
Here is the output:
Second edit:
I uploaded a sample app that highlights the issue. I hope this would help to find a proper solution
Check this link from react docs: React Textarea Value
Basically for textArea react does not supports text enclosed within and you rather need to specify that as value or defaultValue.
The right way thus is
<textarea name="description" value="This is a description." />
or
<textarea name="description" defaultValue="This is a description." />
The difference with value and defaultValue is that specifying defaultValue leaves the component uncontrolled:
With an uncontrolled component, you often want React to specify the initial value, but leave subsequent updates uncontrolled. To handle this case, you can specify a defaultValue attribute instead of value.
...while specifying value instructs React to control the component, meaning you need to update value property to make sure that change is reflected in the component:
Since the value attribute is set on our form element, the displayed value will always be this.state.value, making the React state the source of truth.
To get a clear idea of difference between value / default value check this: Fiddle for value Default Value Distinction Console will always show new value but component will not.
Actually that is exactly what is wrong. From the docs:
If you want to initialize the component with a non-empty value, you can supply a defaultValue prop.
I had the same problem. I solved it by using controlled component, e.g.
state.value = this.props.value
<textarea value={this.state.value} onchange={handler} />
It works fine to control the input part. However, I had another issue, I need to init/change the state.value to props.value whenever there is a re-render.
I used the lift-cycle methods and it works perfect fine.
componentWillReceiveProps: function(){
this.setState({
value: this.props.value
}) }
hope this helps.
Related
Regarding .net core mvc, how do I add and remove classes for <span asp-validation-for="Input.FirstName"> based on a validation error or even between different errors?
<div class="form-group offset-sm-2 col-sm-8">
<label asp-for="Input.FirstName" class="control-label register-heading-style"></label>
<input asp-for="Input.FirstName" class="form-control form-control-valid rounded-0" placeholder="John" />
<span asp-validation-for="Input.FirstName" id="FirstNameError" class="text-danger form-control-invalid invalid-bg"></span>
</div>
Is there a way in JS perhaps to check for errors on input (the errors that are automatically displayed under asp-validation-for="Input.FirstName")?
Thank you
if you want to change class by different error. I think you can't change class per one error. but i think is better use [TempData] and use specific span and show each one when that value is not empty.or null. for this approach you must validate what you need and feel [TempData] for that.
for example:
if(TempData["error"]!=null)
{
<span>this is an error</span>
}
if(TempData["success"]!=null)
{
<span>this is susccess</span>
}
if(TempData["warning"]!=null)
{
<span>this is warning</span>
}
Here is a demo about if the span which id is Input_FirstName-error has error infomation,add class customClass to it.
$(document).ready(function () {
$("#FirstNameError").on('DOMSubtreeModified', function () {
if ($("#Input_FirstName-error").length > 0 && $("#Input_FirstName-error")[0].innerText != "") {
$("#Input_FirstName-error").addClass('customClass');
}
});
});
result:
In my React project, I am using the PrimeReact library to display some Accordions. But I need to create them dynamically and this is the current result:
As you see, the html tags are also shown in the answers of the faqs. I tried using innerHTML and dangerouslySet... but to no success.
Here is my relevant code:
createAccordions = () => {
const allFAQs = this.state.allFAQs;
let accordions = [];
for (const faq of allFAQs) {
const accordion = <AccordionTab header={faq.question} dangerouslySetInnerHTML={{__html: `<p>yo man</p>`}}></AccordionTab>;
accordions.push(accordion);
}
return accordions
}
render() {
return (
<div className="component">
<h1 style={{textAlign: 'center'}}>{this.state.pageTitle}</h1>
<div className="p-grid">
<div className="p-col-3">
</div>
<div className="p-col-6">
<Accordion>
{this.createAccordions()}
</Accordion>
</div>
<div className="p-col-3">
</div>
</div>
</div>
)
}
How can I properly set the innerhtml for the accordions?
I took a look at the source and found that the library tries to render the children you pass to it. I see you tried dangerouslySetInnerHTML, but set it on the AccordionTab itself instead of the child passed into it.
I set up a quick demo on CodePen. I passed in a div container to set the innerHTML on, and it seems to work!
<AccordionTab header="Demo">
<div dangerouslySetInnerHTML={{ __html: "<ul><li>I am HTML</li></ul>" }}></div>
</AccordionTab>
My $(".submitNumberForm").show(900); code in my Template.home.helpers fails to fire-up. However, when the code is run in the browser console, it works perfectly.
The fact that the $(".submitNumberForm").show(900); fails to run in the Template.home.helpers means that an HTML form represented by class name: .submitNumberForm is never shown and remains hidden.
I would be grateful if someone would kindly explain what is wrong with my code.
Find below my helper code: ../client/main.js, pay special attention to the $(".submitNumberForm").show(900);.
Template.home.helpers({
'displaySubmitForm': function () {
var verificationCode = Meteor.user().profile.telephoneNumberVarificationCode;
var verificationCodeTest = Meteor.user().profile.telephoneNumberVarified;
if( typeof verificationCode === 'undefined' && typeof verificationCodeTest === 'undefined'){
console.log("displaySubmitForm verificationCode: " +verificationCode);
console.log("displaySubmitForm verificationCodeTest: " +verificationCodeTest);
alert("displaySubmitForm: TRUE");
$(".submitNumberForm").show(900);
return true;
}
else {
alert("displaySubmitForm: FALSE");
$(".submitNumberForm").hide(900);
return false;
}
}
});
When the home page is refreshed, the browser console prints out:
displaySubmitForm verificationCode: undefined
displaySubmitForm verificationCodeTest: undefined
and the alert function displays a popup displaying: displaySubmitForm: TRUE, however the $(".submitNumberForm").show(900); doesn't fire-up!
Find below my: <template name="home"> code ../client/main.html. Note that The {{displaySubmitForm}} at the top/begining of the template, displays the words true, however the rest of the HTML form submitNumberForm doesn't display at all. This, again is an indication that the $(".submitNumberForm").show(900); code doesn't fire-up
<template name="home">
{{displaySubmitForm}}
{{#if displaySubmitForm}}
<div class="form-group submitNumberForm">
<div class="col-sm-10">
<input type="number" class="form-control" id="telephoneNumber" placeholder="Enter Number" name="telephoneNumber">
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="button" id="submitNumber" class="btn btn-primary btn-block">Submit</button>
</div>
</div>
</div>
{{else}}
{{/if}}
</template>
Find below my CSS file: .../client/main.css
.submitNumberForm{
display: none;
}
Just to clarify, the html form submitNumberForm is meant to be hidden by default and only show $(".submitNumberForm").show(900); based on the conditions specified in the Template.home.helpers
Again, when I copy code from the helper, paste and run in the console, the Html form submitNumberForm appears. Can anyone kindly explain to me why this $(".submitNumberForm").show(900); doesn't fire-up in the helper as its supposed to do?
When you use {{#if displaySubmitForm}} it means: Generate the html code between the {{#if}} and {{/if}} tags when the displaySubmitForm helper returns true.
The html elements inside your if doesn't exist when your helper is executing.
So your selector: $(".submitNumberForm") in your code doesn't select anything, because the submitNumberForm element doesn't exist yet.
After that, it works on the console because the helper already executed and the html is now generated.
I am pretty much new to React so apologies for lack of code here.
Lets say I have a text field which shows the name of a user. When I click a button, I want this field to be editable.
Can this be done in ReactJS?
Use like this,
ES6 js:
class App extends React.Component{
constructor(){
super()
this.state={disable:true,
val:"username"}
}
handleClick(e){
this.setState({disable:!this.state.disable})
}
render(){
return(
<div className="wrapper">
<input type="text" disabled={this.state.disable} value={this.state.val}/>
<input type="button" value="Enable/Disable" onClick={this.handleClick.bind(this)}/>
</div>
)
}
}
Working Jsbin
I am new to Angularjs. I've tried a example in here.
file index.html:
<div ng-repeat="data in ctl.dataList">
<div class="col-md-6">
<textarea type="text" ng-mouseover="ctl.mouseOverFunc()" ng-mouseleave="ctl.mouseLeaveFunc()">{{data.value}}</textarea>
<button ng-show="ctl.showCloseBtn">X</button>
</div>
</div>
file app.js:
app.controller('FocusController', function() {
this.showCloseBtn = false;
this.dataList = [{
value: "one"
}, {
value: "two"
}];
this.mouseOverFunc = function() {
this.showCloseBtn = true;
};
this.mouseLeaveFunc = function() {
this.showCloseBtn = false;
};
});
I want to show close button when mouse overed every textarea like facebook chat in this picture. But my issues is when mouse over one of textarea then all X button was showed.
How do i assign dynamic controller to every textarea or how to do like facebook chat ?
Thanks for your help
You can do with CSS as well as AngularJS. I suggest you to do with CSS which is Simple. And Do your ng-click on the button.
This Plunker Demo is using with CSS and added ng-click there. Please check the styles and classes added.
Styles
<style>
.field:hover .btn-close {
display:block;
}
.btn-close {
display:none;
}
</style>
HTML
<div ng-repeat="data in ctl.dataList">
<div class="col-md-7 field">
<textarea></textarea>
<button ng-click="doSomething()" class="btn-close">X</button>
</div>
</div>
This Plunker Demo is with AngilarJS as explained in the other answer by New Dev.
<div ng-repeat="data in ctl.dataList">
<div ng-mouseover="data.showX = true"
ng-mouseleave="data.showX = false">
<textarea></textarea>
<button ng-click="doSomething()" ng-show="data.showX">X</button>
</div>
Typically, it would be best to create a directive for this functionality and encapsulate all the logic of clicking the "x" button, but for simplicity you could also leverage the child scope created by ng-repeat, and do the following:
<div ng-repeat="data in ctl.dataList">
<div ng-mouseover="data.showX = true"
ng-mouseleave="data.showX = false">
<textarea type="text"></textarea>
<button ng-show="data.showX" ng-click="ctl.close(data)">X</button>
</div>
</div>
ng-repeat="item in items" creates a child scope for each item, so you can set values on the child scope.
Here's your modified plunker
EDIT:
As suggested in the comments, if you have nothing more complex than showing or hiding the button, definitely CSS approach is the simplest way to go. Use the above example then as an illustration for how scopes work.