I have two function in Reactjs. When function one call a function of function two. There have error same as
"Uncaught TypeError: this.props.onButonShowClick is not a function"
This is function one :
var HiddenEdit = React.createClass({
_handleOnClick: function(e) {
e.preventDefault(),
this.props.onButonShowClick(true);
},
render: function() {
return (<span className="col-lg-2 btn-action-group">
<a className="add btn-for-view" href={this.props.url_detail} id="btn-add-chapter-123" title="Add"></a>
<a className="edit btn-for-view" onClick={this._handleOnClick} id={this.props.id_chapter} title="Edit"></a>
<a className="trash btn-for-delete btn-delete-episode" data-confirm="Are you sure?" rel="nofollow" data-method="delete" href=""></a>
</span>);
}
});
And this is a function two
var ChapterList = React.createClass({
_handleOnPaginate: function(pageNumber) {
this.props.inPagenate(pageNumber)
},
getInitialState: function () {
return {
childVisible: false
};
},
_handleOnClick: function(params) {
this.state.childVisible = params;
},
render: function() {
var showEdit = this.state.childVisible;
var chapterNodes = this.props.data.chapters.map(function(chapter, index) {
var url_chapter_detail = "/admin/chapters/" + chapter.chapter_id + "/chapter_details";
var btn_edit = "btn-edit-chapter-" + chapter.chapter_id;
var href_delete = "/admin/mangas/" + chapter.manga_id + "/chapters/" + chapter.chapter_id;
var div_chapter = "chapter-" + chapter.chapter_id;
return (<div className="row item-data" id={div_chapter}>
<div className="text-data-row">
<input value={chapter.chapter_id} type="hidden" className="chapter[manga_id]" id="chapter_manga_id" />
<span className="col-lg-1">
<input className="form-control" disabled="disabled" type="text" value={chapter.chapter_order} name="chapter[chapter_order]" id="chapter_chapter_order" />
</span>
<span className="col-lg-5">
<input className="form-control" disabled="disabled" type="text" value={chapter.chapter_name} name="chapter[chapter_name]" id="chapter_chapter_name" />
</span>
<span className="col-lg-2">
<input className="form-control" disabled="disabled" type="text" value={chapter.by_group} name="chapter[by_group]" id="chapter_by_group" />
</span>
{
showEdit ? <ShowEdit url_detail={url_chapter_detail} id_chapter="btn_edit" /> : <HiddenEdit onButonShowClick={this._handleOnClick} url_detail={url_chapter_detail} id_chapter="btn_edit" />
}
</div>
</div>);
});
return (<div className="form-post-movie" id="form-post-movie" role="form">
<div className="col-lg-12">
<div className="list-data">
{chapterNodes}
</div>
</div>
</div>
<div className="div-page">
<PaginatorSection totalPages={this.props.data.meta.total_pages} currentPage={this.props.data.meta.current_page} onPaginate={this._handleOnPaginate} />
</div>
</div>);
}
});
Can anyone help me solve this?
Well, this is undefined inside the callback of an array map. (Array.prototype.map() docs)
And so will be the value passed as onButtonShowClick prop.
<HiddenEdit onButonShowClick={this._handleOnClick} url_detail={url_chapter_detail} id_chapter="btn_edit" />
You should fix it by passing this as the second parameter of that map:
var chapterNodes = this.props.data.chapters.map(function(chapter, index) { /*...*/ }, this);
Also, you should take a look at React's docs about dynamic children.
Related
I am trying to set up some functionality on this React component so that a user can add and remove empty radio button options to a page that a user can type text into. The only issue that I am having is that I am relatively new to React and am not 100% how to do this.
import React, { Component } from 'react';
class TextRadio extends Component {
constructor() {
super();
state = {
textValue: ""
}
};
handleInputChange = event => {
const value = event.target.value;
const name = event.target.name;
this.setState({
[name]: value
});
}
addBox = () => {
}
removeBox = () => {
}
render() {
return(
<div>
<div className="form-check">
<input className="form-check-input" type="radio" id="" name="" value="" />
<label className="form-check-label" for="">
<input class="form-control" type="text" placeholder="" />
</label>
</div>
<div className="form-check">
<input className="form-check-input" type="radio" id="option" name="option" value="option" />
<label className="form-check-label" for="option">
<input class="form-control" type="text" placeholder="" />
</label>
</div>
<div className="form-check">
<input className="form-check-input" type="radio" id="option" name="option" value="option" />
<label className="form-check-label" for="option">
<input class="form-control" type="text" placeholder="" />
</label>
</div>
<button type="button" className="btn btn-primary" onClick={this.addBox}>
Add Option
</button>
<button type="button" className="btn btn-danger" onClick={this.removeBox}>
Remove Option
</button>
</div>
);
}
}
export default TextRadio;
The result that I am expecting to happen is to have it so the component can add and remove radio button options from the page depending on the button that the user presses
i was completed just your addBox and RemoveBox functions, i hope that's help you
import React, { Component } from "react";
class TextRadio extends Component {
constructor() {
super();
this.state = {
radioButtons: []
};
}
handleInputChange = event => {
const value = event.target.value;
const name = event.target.name;
};
addBox = () => {
this.setState(prevstate => {
let radioButtons = prevstate.radioButtons;
if (radioButtons.length === 0) {
radioButtons.push({
id: 1,
name: "radiobutton",
value: "test"
});
return {
radioButtons: radioButtons
};
} else {
radioButtons.push({
id: radioButtons[radioButtons.length - 1].id + 1,
name: "raiodButton_" + (radioButtons[radioButtons.length - 1].id + 1),
value: radioButtons[radioButtons.length - 1].value
});
return {
radioButtons: radioButtons
};
}
});
};
removeBox = () => {
this.setState(prevstate => {
let radioButtons = prevstate.radioButtons;
if (radioButtons.length !== 0) {
radioButtons.pop(radioButtons[radioButtons.length - 1]);
return {
radioButtons: radioButtons
};
} else {
return { radioButtons: radioButtons };
}
});
};
render() {
return (
<div>
<div className="form-check">
{this.state.radioButtons.map(radiobutton => {
return (
<div>
<input
className="form-check-input"
type="radio"
id={radiobutton.id}
name={radiobutton.name}
value={radiobutton.value}
/>
<label className="form-check-label" for="">
<input class="form-control" type="text" placeholder="" />
</label>
</div>
);
})}
</div>
<button type="button" className="btn btn-primary" onClick={this.addBox}>
Add Option
</button>
<button
type="button"
className="btn btn-danger"
onClick={this.removeBox}
>
Remove Option
</button>
</div>
);
}
}
export default TextRadio;
https://codesandbox.io/embed/confident-browser-tmojp
I was playing around with your idea and made some changes in the code, just to show you an example, how you can dynamically create new components and store them in applications state and then render out to user based on their actions.
I created new component just for form UI: option, input field and remove button. If user clicks on the Add Option, new item of the component is added to application state and then render out. Remove button is used to remove Item from state.
class TextRadio extends Component {
state = {
optionInputs: []
};
addBox = () => {
const optionInputsUpdated = [
...this.state.optionInputs,
<OptionInput id={uuid.v4()} remove={this.removeBox} />
];
this.setState({ optionInputs: optionInputsUpdated });
};
removeBox = id => {
const optionInputsUpdated = this.state.optionInputs.filter(
item => item.props.id !== id
);
this.setState({ optionInputs: optionInputsUpdated });
};
render() {
return (
<div>
{this.state.optionInputs.map((optionInput, idx) => {
return (
<div key={idx} test="123">
{optionInput}
</div>
);
})}
<button type="button" className="btn btn-primary" onClick={this.addBox}>
Add Option
</button>
</div>
);
}
}
const OptionInput = props => {
return (
<div className="form-check">
<input
className="form-check-input"
type="radio"
id=""
name="radio"
value=""
/>
<label className="form-check-label" for="">
<input className="form-control" type="text" placeholder="" />
</label>{" "}
<button
type="button"
className="btn btn-danger"
onClick={() => props.remove(props.id)}
>
Remove Option
</button>
</div>
);
};
Hope this gives you better understanding, how to achieve your goal.
If you need additional help, just post a comment under this answer, and I will update demo to help you.
Here is DEMO I created from your code: https://codesandbox.io/s/nice-ganguly-s4wls
first you have to initialize an empty array state
this.state={
radioButtons : [{input:''}]
}
then in your return statement you have to loop through the radioButtons array and show the radio button with input
{
this.state.radioButtons.map(item => (
<div className="form-check">
<input className="form-check-input" type="radio" id="option" name="option" value="option" />
<label className="form-check-label" for="option">
<input class="form-control" type="text" placeholder="" />
</label>
</div>
))
}
then in your addBox function append an object on every click
addBox = () => {
this.setState({radioButtons:[...this.state.radioButtons, {input:''}]})
}
function to remove a radio button object
removeBox = () => {
let radioArray = this.state.radioButtons
radioArray.pop()
this.setState({radioButtons:radioArray})
}
Final code Looks like this :
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component{
constructor(props){
super(props);
this.state={
radioButtons :[{input:''}]
}
}
addBox = () => {
this.setState({radioButtons:[...this.state.radioButtons, {input:''}]})
}
removeBox = () => {
let radioArray = this.state.radioButtons
radioArray.pop()
this.setState({radioButtons:radioArray})
}
render(){
return(
<div>
{
this.state.radioButtons.map(item => (
<div className="form-check">
<input className="form-check-input" type="radio" id="option" name="option" value="option" />
<label className="form-check-label" for="option">
<input class="form-control" type="text" placeholder="" />
</label>
</div>
))
}
<button type="button" className="btn btn-primary" onClick={this.addBox}>
Add Option
</button>
<button type="button" className="btn btn-danger" onClick={this.removeBox}>
Remove Option
</button>
</div>
)
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
codepen Example
const AnswerGrid = React.createClass({
getInitialState: function(){
return {active: null};
},
radioClick: function(e){
this.setState({active: e.target.value});
},
render : function(){
return (
<li className="answerOption">
<input type="radio" onChange={this.radioClick} id={this.props.answer.answer_id} className="radioCustomButton" name={this.props.question_id} value={this.props.answer.answer_id}/><br/>
<label className="radioCustomLabel">{this.props.answer.title}</label>
</li>
);
}
});
This is my components call AnswerGrid
const QuestionGrid = React.createClass({
render : function(){
var rows = [];
console.log(this.props.active);
//console.log(this.props.question);
var question_id = this.props.question.question_id;
this.props.question.list_answer.map(function(answer){
rows.push(<AnswerGrid key={answer.answer_id} answer={answer} question_id={question_id} />);
});
return (
<div className="row">
<div className="col-md-12">
<h2 className="question"><b>{this.props.question.question_title}</b></h2>
<input type="type" className="rs" name="rs" value={this.props.active} /><br/>
<ul className="answerOptions">
{rows}
</ul>
<hr/>
</div>
</div>
);
}
});
I am using QuestionGrid to display list li with input from AnswerGrid
When i use value={this.props.active} at QuestionGrid , it not working.
Pls help me fix it
I'm in a bit of a bind here. The code should be right, but Chrome keeps saying there's a uncaught type reference on line 27.
It can't read the property 'name' of null. I've gone over this code about three times already and can't find why its giving me issues.
Was hoping another set of eyes could take a look.
var React = require("react");
var actions = require("../actions/SchoolActions");
module.exports = React.createClass({
getInitialState: function () {
return {
name: "",
tagline: "",
};
},
addSchool: function (e) {
e.preventDefault();
actions.addSchool(this.state);
},
handleInputChange: function (e) {
e.preventDefault();
var name = e.target.name;
var state = this.state;
state[name] = e.target.value;
this.setState(state);
},
render: function () {
return (
<form className="form" onSubmit={this.addSchool}>
<div className="form-group">
<label className="control-label" htmlFor="name">
School Name:
</label>
<input
type="text"
className="form-control"
id="name"
name="name"
value={this.state.name}
onChange={this.handleInputChange}
placeholder="School Name"
/>
</div>
<div className="form-group">
<label className="control-label" htmlFor="tagline">
Tagline:
</label>
<input
type="text"
className="form-control"
id="tagline"
name="tagline"
value={this.state.address}
onChange={this.handleInputChange}
placeholder="Tagline"
/>
</div>
<div className="form-group">
<button className="btn" type="submit">
Add School
</button>
</div>
</form>
);
},
});
I have a custom directive that is an ng-modal window. My issue is when I set one of the fields(patientId) on show in code, the form's $valid won't update to true even tho all the required fields are true. When I updated the patientid field thru the UI, $valid updates correctly. Since the field in question is disabled in current cases, I can't rely on the user manually updated the field. As a quick fix I used the $error.required for the disable for the Save button but want to do it the correct way.
'use strict';
var mod
try {
mod = angular.module('DCI');
}
catch (err) {
mod = angular.module('DCI', []);
}
mod.directive('labResultEntry', function () {
return {
restrict: 'E',
scope: {
labRanges: '=',
show: '=',
patientList: '=',
editResult: '=',
saveLabCallback: '='
},
replace: true,
link: function (scope, element, attrs) {
scope.dialogStyle = {};
scope.result = {};
scope.autoComplateControl1 = {};
scope.autoComplateControl2 = {};
scope.result.SensitiveData = 'N';
scope.editdisable = scope.isOpen = false;
var rootScope = scope.$parent;
if (attrs.saveResultCallback)
scope.saveResultCallback = attrs.saveResultCallback
if (attrs.width)
scope.dialogStyle.width = attrs.width;
if (attrs.height)
scope.dialogStyle.height = attrs.height;
scope.$watch('show',
function () {
if (scope.show == true) {
if (scope.editResult != undefined) {
scope.editdisable = true;
scope.autoComplateControl1.insertInput(rootScope.patientName);
scope.result.patientId = rootScope.patientId;
scope.result.sampledate = scope.editResult.sampledate;
scope.result.TestCode = scope.editResult.TestCode
scope.result.Result = parseFloat(scope.editResult.Result);
scope.result.LabResultId = scope.editResult.LabResultId;
angular.forEach(scope.labRanges, function (test) {
if (test.TestCode == scope.editResult.TestCode) {
scope.result.TestDescription = test.TestDescription;
scope.result.ShortName = test.ShortName;
scope.result.MaxValue = test.MaxValue;
scope.result.MinValue = test.MinValue;
scope.result.UOM = test.UOM;
scope.autoComplateControl2.insertInput(test.TestDescription);
}
})
}
else
scope.editdisable = false;
SetPatientId();
}
}, true);
function SetPatientId() {
if (rootScope.patientId) {
scope.autoComplateControl1.insertInput(rootScope.patientName);
rootScope.safeApply(function(){
scope.result.patientId = rootScope.patientId;
});
}
else {
if (scope.autoComplateControl1.clearnInput != undefined) {
scope.autoComplateControl1.clearnInput();
}
scope.result.patientId = undefined;
}
};
function reset() {
scope.result = {};
scope.result.SensitiveData = 'N';
SetPatientId();
scope.autoComplateControl2.clearnInput();
scope.editResult = undefined;
};
scope.hideModal = function () {
reset();
scope.show = false;
};
scope.autoCompleteSelect = function (item) {
if (item) {
scope.result.MaxValue = item.description.MaxValue;
scope.result.MinValue = item.description.MinValue;
scope.result.UOM = item.description.UOM;
scope.result.ShortName = item.description.ShortName;
scope.result.TestCode = parseFloat(item.description.TestCode, 10);
scope.result.TestDescription = item.description.TestDescription;
}
};
scope.open = function ($event) {
$event.preventDefault();
$event.stopPropagation();
scope.isOpen = true;
};
scope.selectPatient = function (item) {
if (item) {
var found = false;
angular.forEach(scope.patientList, function (itemp) {
if (item.originalObject.PatientId = itemp.PatientId)
found = true;
});
if (found)
scope.result.patientId = item.originalObject.PatientId;
}
};
scope.LookUpTestCode = function () {
angular.forEach(scope.labRanges, function (test) {
if (test.TestCode == scope.result.TestCode) {
scope.result.TestDescription = test.TestDescription;
scope.result.ShortName = test.ShortName;
scope.result.MaxValue = test.MaxValue;
scope.result.MinValue = test.MinValue;
scope.result.UOM = test.UOM;
scope.autoComplateControl2.insertInput(test.TestDescription);
}
})
};
scope.saveResult = function () {
var result = {};
angular.copy(scope.result, result);
result.labLocation = "002060";
scope.saveLabCallback(result);
scope.hideModal()
};
},
template: "HTML code below as single string"
<div class="ng-modal colored-header" ng-show="show">
<div class="ng-modal-overlay" ng-click="hideLabModal()"></div>
<div class="ng-modal-dialog md-content" ng-style="dialogStyle">
<div class="modal-header">
<div class="ng-modal-close" ng-click="hideModal()">X</div>
<h3>Lab Result</h3>
</div>
<div class="ng-modal-dialog-content">
<form name="labEntry" role="form" class="modal-body">
<div angucomplete-alt id="ex2" placeholder="Patient*" maxlength="50" pause="400" selected-object="selectPatient" local-data="patientList" field-required="!result.patientId"
field-required-class="ng-invalid" search-fields="PatientName" disable-input="editdisable" title-field="PatientName" minlength="4" input-class="form-control-small form-control" match-class="highlight" control="autoComplateControl1" />
<br />
<input class="form-control col-xs-9 col-sm-9 col-md-9" style="margin-top: 3px; margin-bottom: 3px;" type="text" ng-disabled="true" ng-model="result.labLocation" placeholder="OTHER (LAB)" />
<br />
<br />
<br />
<input ng-style="{ 'border-color' : (labEntry.TestCode.$valid == false ? 'red' : 'null') }" name="TestCode" class="form-control col-xs-9 col-sm-9 col-md-9" ng-disabled="editdisable" ng-required="!result.TestCode" ng-model="result.TestCode" placeholder="Test code*" ng-blur="LookUpTestCode()" />
<br />
<br />
<br />
<div angucomplete-alt id="ex3" placeholder="Description*" maxlength="50" pause="400" selected-object="autoCompleteSelect" local-data="labRanges"
search-fields="TestDescription" disable-input="editdisable" title-field="TestDescription" minlength="4" input-class="form-control form-control-small" match-class="highlight" control="autoComplateControl2" />
<br />
<input ng-style="{ 'border-color' : (labEntry.Result.$valid == false ? 'red' : 'null') }" style="margin-top: 3px; margin-bottom: 3px;" name="Result" class="form-control col-xs-9 col-sm-9 col-md-9" ng-required="!result.Result" ng-model="result.Result" placeholder="Result*" />
<br />
<br />
<br />
<p class="input-group">
<input name="sdate" ng-style="{ 'border-color' : (labEntry.sdate.$valid == false ? 'red' : 'null') }" class="input-group-addon form-control" is-open="isOpen" datepicker-popup="MM/dd/yyyy" ng-required="!result.sampledate" ng-model="result.sampledate"
placeholder="Sample Date*" />
<span class="input-group-btn">
<span class="input-group-addon btn btn-primary" ng-click="open($event)"><i class="glyphicon glyphicon-th"></i></span>
</span>
</p>
<input class="col-xs-6 col-sm-6 col-md-6" type="text" ng-disabled="true" ng-model="result.MinValue" placeholder="Range Min" />
<input class="col-xs-6 col-sm-6 col-md-6" type="text" ng-disabled="true" ng-model="result.MaxValue" placeholder="Range Max" />
<br />
<br />
<input class="col-xs-6 col-sm-6 col-md-6" type="text" ng-disabled="true" ng-model="result.UOM" placeholder="UOM" />
<br />
<br />
<input type="checkbox" class="iCheck" icheck ng-model="result.SensitiveData" ng-true-value="'Y'" ng-false-value="'N'" /> Sensitive Data
<br />
<br />
<textarea class="form-control" rows="4" placeholder="comments..." ng-model="result.Comment"></textarea>
</form>
<div class="modal-footer">
<button type="button" class="btn btn-flat md-close" ng-click="hideModal()">Cancel</button>
<button type="button" class="btn btn-flat btn-success" ng-disabled="!labEntry.$valid" ng-click="saveResult()">Save</button>
</div>
</div>
</div>
</div>
The digest() method might help:
add this function to the end and call it from any function that changes values to the scope after everything is set:
function digest() {
if ( scope.$$phase !== '$apply' && scope.$$phase !== '$digest' ) {
scope.$digest();
}
}
You can get more Info on the digest function on Angulars Website:
Processes all of the watchers of the current scope and its children.
Because a watcher's listener can change the model, the $digest() keeps
calling the watchers until no more listeners are firing.
https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$digest
I hope this helps.
Figured it out. It was an issue with Autocomplete-alt directive I was using. Updated to 1.1.0 and it solved it.
I have this knockout code.
self.newPatient = ko.asyncCommand({
execute: function(complete) {
var isValid=$('#addPatientForm').parsley( 'validate' );
if(isValid){
var patientJson=ko.toJSON(self.patient());
formdata.append("json",patientJson);
//self.enableButton(false);
var imagepath= $.ajax({
url: projectUrl+"newPatient",
type: "POST",
data: formdata,
processData: false,
contentType: false,
success: function (res) {
formdata = new FormData();
imagepath=res;
var length=self.patients().length;
var patient=self.patient();
// self.enableButton(true);
}
});
}
},
canExecute: function(isExecuting) {
return !isExecuting && isDirty() && isValid();
}
});
This is my html inputfields
<div class="control-group">
<label class="control-label" for="inputIcon">Username :</label>
<div class="controls">
<div class="input-prepend">
<span class="add-on"><i class="icon-hand-right"></i></span>
<input class="span8" type="text" data-bind="value: username" name="username" data-required="true" data-trigger="change" data-remote="${pageContext.request.contextPath}/isUserNameExists" data-remote-method="GET">
</div>
</div>
</div>
<div class="control-group">
<label class="control-label" for="inputIcon">Password :</label>
<div class="controls">
<div class="input-prepend">
<span class="add-on"><i class="icon-hand-right"></i></span>
<input class="span8" type="password" data-bind="value: password" name="password" data-required="true" data-trigger="change">
</div>
</div>
</div>
and this is my button
<button class="btn btn-primary"
data-bind="command: $root.newPatient, activity: $root.newPatient.isExecuting">
<i class="icon-ok icon-white"></i> Save
</button>
when I press the save button then execute: function(complete){.....} is called and inside this function
var isValid=$('#addPatientForm').parsley( 'validate' );
is called which checks form validity and if the form is invalid then isValid is false and hence the ajax is not called.
I want to call
var isValid=$('#addPatientForm').parsley( 'validate' );
if(isValid){.....}
when any of the input field is changed .So can any body please suggest me how to do?
You could write your own bindingHandler:
ko.bindingHandlers.parsley = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var isValid = valueAccessor();
var $form = $(element).closest('form');
$(element).change(function() {
isValid($form.parsley('validate'));
});
}
};
And in your ViewModel:
self.isValid = ko.observable(false);
And then:
<form ...>
<input data-bind="parsley: isValid, ..." />
</form>
See http://jsfiddle.net/sjroesink/ksqXx/
Edit
Without being able to reproduce your error, or an actual line where the error occurs, I cannot help you.
Try using Chrome's Developer tools to see where the error occurs:
You could use the subscribe function of your observable to run code:
username.subscribe(function () { isValid=$('#addPatientForm').parsley( 'validate' ); }
password.subscribe(function () { isValid=$('#addPatientForm').parsley( 'validate' ); }
Update after your comment:
Here is what I would do:
<div id='koRoot'>
<input type='text' data-bind='value: username' />
<input type='text' data-bind='enable: enableButton,value: password' />
<input type='button' data-bind='command: newPatient' value='Go!' />
</div>
...
And the js:
var callNewPatient = function () {
if (self.awaitingValidation()) self.newPatient.execute();
}
this.username.subscribe(callNewPatient);
this.password.subscribe(callNewPatient);
this.newPatient = ko.asyncCommand({
execute: function (complete) {
self.isValid(self.username() === 'me' && self.password() === 'pass');
if (self.isValid()) {
self.awaitingValidation(false);
alert("Valid!");
} else {
self.awaitingValidation(true);
}
},
canExecute: function (isExecuting) {
return self.isValid();
}
});
http://jsfiddle.net/nyothecat/LkaEJ/1/