As part of my application I have the following function in my react class for updating the state:
updateReplies(minorRevision, ParentCommentId) {
const ids = allComments.map(object => {
return object.Id;
});
console.log(ParentCommentId);
const localId = allComments[allComments.length - 1].LocalId + 1;
const itemId = this.state.currentUser.ItemId;
const name = this.state.currentUser.Name;
const newId = Math.max(...ids) + 1;
const comment = this.state.textAreaComment;
const recipients = this.state.selectedValues;
const commentDate = toIsoString(new Date());
const newComment = {
AttachmentId: null, Comment: comment, Commenter: { ItemId: itemId, Name: name },
Id: newId, IsDeleted: false, LocalId: localId, MinorRevision: minorRevision, ParentCommentId: ParentCommentId,
Recipients: recipients, Time: commentDate
};
allComments.push(newComment);
const groupedComments = groupByRevision(allComments);
this.setState({ Comments: groupedComments });
saveReply();
};
This is then past through a couple of functions before coming to the one where I will be passing the parameters through:
export function GetComments(props) {
return (
<React.Fragment>
{props.commentsArray.map((comment, index) => {
const localId = comment.LocalId;
const parentCommentId = comment.ParentCommentId;
const parentLocalId = allComments.filter(obj => obj.Id === parentCommentId);
const recipients = comment.Recipients;
let recipientsArray = [];
let recipientsList;
recipients.forEach(function (arrayItem) {
recipientsArray.push(arrayItem.Name);
recipientsList = recipientsArray.join(', ');
});
const date = new Date(comment.Time);
const formattedDate = date.toLocaleDateString() + " " + ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2);
return (
<div key={localId} className="comment-container">
<div key={comment.Commenter.ItemId} className="commenter">
<span className="id-label">{localId}</span>
{parentCommentId && (
<span className="reply" title={`in reply to ${parentLocalId[0].LocalId}`}>
<a className="reply" href={"#c" + parentLocalId[0].LocalId}>⤵</a> </span>
)}
<span><a id={"c" + localId} name={"c" + localId}>{comment.Commenter.Name}</a></span>
<div className="comment-actions-container">
<button type="button" className="btn-reply" data-value={comment.Id} title="Reply to comment" data-toggle="modal" data-target="#dlg-new-reply">💬</button>
</div>
</div>
<div className="modal fade" id="dlg-new-reply" tabIndex="-1" role="dialog" aria-labelledby="modalLabelLarge" aria-hidden="true">
<div className="modal-dialog modal-lg">
<div className="modal-content">
<div className="modal-header">
<h4 className="modal-title" id="modalLabelLarge">Reply</h4>
</div>
<div className="modal-body">
<span id="current-comment-display">{"Currently selected: " + comment.Id}</span>
<div className="address-list-container">
<Select placeholder="Send to ..." id="cboAddressees" isMulti name="addressees" onChange={props.getSelected} options={options} />
</div>
<textarea id="txtReply" onChange={props.getTextComment} name="reply"></textarea>
</div>
<div className="modal-footer">
<button type="button" className="btn" data-dismiss="modal" aria-label="Cancel">
<span aria-hidden="true">Cancel</span>
</button>
<button id="save-reply" type="button" onClick={() => props.setChange(comment.MinorRevision, comment.Id)} className="btn">Save</button>
</div>
</div>
</div>
</div>
<div id={"recipients-" + comment.Id} className="recipients">{recipientsList}</div>
<div className="comment">{comment.Comment}</div>
<div className="comment-footer">{formattedDate}</div>
<GetReplies Id={comment.Id} />
</div>
);
})}
</React.Fragment>
);
}
Now for here, for each comment I am rendering these elements and this works fine however, when we get to this part:
<button id="save-reply" type="button" onClick={() => props.setChange(comment.MinorRevision, comment.Id)} className="btn">Save</button>
I am having some issues, I am not getting any errors but the wrong values are getting passed through, instead of the MinorRevision and Id of that individual comment, it is just passing through the values of the very last comment if that makes sense.
What I am finding confusing is that for the rest of it, I am not having that issue like for example in here:
<button type="button" className="btn-reply" data-value={comment.Id} title="Reply to comment" data-toggle="modal" data-target="#dlg-new-reply">💬</button>
I am getting the correct Id, so at the moment the highest Id value is 158 and MinorRevision value is 2 and no matter which element I am clicking on, that is what is passed through props.SetChange and I have no idea why that would be the case
Edit -
So the problem seems to be with using bootstrap modal and I have no idea why this would be happening. When the modal is opened, it will show the very last of the comment objects but everything underneath the modal i.e:
<div className="comment">{comment.Comment}</div>
will show the correct values, so it is something to do with the modal but I'm just not sure what
Related
I'm stuck in the image array where I can patch image array value in my edit form there can I upload other images or push images that array or delete.
I have a product model where I can have a sub-array where I can trigger edit query or patch value.
onSelectFile(event: any) {
if (event.target.files && event.target.files[0]) {
var filesAmount = event.target.files.length;
for (let i = 0; i < filesAmount; i++) {
var reader = new FileReader();
reader.onload = (event: any) => {
console.log("image1",event.target.result);
this.urls.push(event.target.result);
};
reader.readAsDataURL(event.target.files[i]);
}
}
}
<div class="fileupload-wrapper">
<div>
<button class="file-upload-button" type="button" for="custom-fileupload">
<img src="assets/images/icons/file-upload.svg"
alt="file-upload"><span>Upload</span>
<input type="file" accept="image/*;base64," id="file" #file
(change)="onSelectFile($event)" id="custom-fileupload" class="custom-fileupload" multiple />
</button>
</div>
<span class="file-info">
<div *ngFor='let url of urls; let i = index' class="category-wrapper">
<img [src]="sanitizeImageUrl(url)" *ngIf="url" class="categroy-images">
<span (click)="resetCoverValue(i)" class="cross-icon">{{ this.documentName ?
"close" : null }}
<img src="assets/images/icons/blue-cross.svg">
</span>
</div>
</span>
</div>
here in my code i m toggling a panel on the basis of click event when clicked it will show and when again clicked on the same button it will disappear. but what i want when i will click outside the button anywhere the panel should close, how do i do that?
function Project(props) {
const [rightPanel, setrightPanel] = useState(false);
function projectToggle () {
if(!rightPanel) setrightPanel(true);
else setrightPanel(false);
}
return (
<React.Fragment>
<div className="vh-ce-align pd-b-10 mg-b-5 bo-bottom-grey">
<div className="button-blue" onClick={projectToggle}>Create New Project</div>
</div>
<div className="d-flex">
{rightPanel ? (<div className="right-side-panel">
<div className="mg-b-20">
<div className="fw-bold mg-b-10">Client Id</div>
<input type="text" className="right-side-input"/>
</div>
<div className="mg-b-20">
<div className="fw-bold mg-b-10">Frequency</div>
<div className="wd-pct-100 d-flex pd-b-5 bo-bottom-grey">
<div className="flex-one">Annually</div>
<i className="fas fa-chevron-down mg-r-10"></i>
</div>
</div>
<div className="mg-b-20">
<div className="fw-bold mg-b-10">Year</div>
<div className="wd-pct-100 d-flex pd-b-5 bo-bottom-grey">
<div className="flex-one">Select Year</div>
<i className="fas fa-chevron-down mg-r-10"></i>
</div>
</div>
</div>): null}
</div>
</React.Fragment>
)
}
Try this code below.
const handleClickClosePanelFromOutside = (e) => {
if (e.target.className !== "button-blue") {
setRightPanel(false);
}
}
useEffect(() => {
document.body.addEventListener("click", handleClickClosePanelFromOutside)
return () => {
document.body.removeEventListener("click", handleClickClosePanelFromOutside)
}
})
What you're looking for is an event type to attach an event handler function to ... And, in this case, the not so obvious answer is a blur (opposite of focus) event. When anything in the DOM observes a user interaction after the button is clicked, the button will receive an onblur event.
I receive this error:
TypeError: this.state is null
Have code like this, but it does not work .... Any idea why?
I want to change the text of a label (reanalyzeButton)
Read several docs and tutorials and it seem it should work. No idea why it behaves like this.
This is inherited code I work with using React 0.13
var ProjectHeader = React.createClass({
displayName: 'ProjectHeader',
intervalId: null,
state: {
projectjson: [],
label: '',
},
componentDidMount() {
// Now we need to make it run at a specified interval
this.intervalId = setInterval(this.refresh, 1000);
this.setState({ label: '<span><i className="octicon octicon-sync" /> Project queued for analysis: <strong>{queuePosition}</strong>.</span>'});
},
refresh : function(){
if (this.state.projectjson.analysis_status == 'succeeded') {
clearInterval(this.intervalId);
this.setState({label: '<A onClick={this.analyzeProject} title="Request an analysis of the project"><i className="octicon octicon-sync"/> Check for new commits</A>'});
}
render : function(){
if (props.project.analysis_status == 'in_progress') {
//reanalyzeButton = <A onClick={this.analyzeProject} title="Request a re-analysis of the project"><i className="fa fa-refresh fa-spin" /> Analysis in progress</A>
reanalyzeButton = this.state.label
} else if ((!props.project.analyze) || props.project.analysis_priority == 0) {
//reanalyzeButton = <A onClick={this.analyzeProject} title="Request an analysis of the project"><i className="octicon octicon-sync"/> Check for new commits</A>
reanalyzeButton = this.state.label
} else {
//reanalyzeButton = <span><i className="octicon octicon-sync" /> Project queued for analysis: <strong>{queuePosition}</strong>.</span>
reanalyzeButton = this.state.label
}
return <div className="project-header" itemScope itemType="http://schema.org/Code">
<div className="row">
<div className="col-xs-12 col-sm-9">
<div className="clearfix">
{projectHeader}
</div>
</div>
<div className="col-xs-12 col-sm-3">
<span className="qc-badge">
{badge}
</span>
</div>
</div>
<div className="row">
<div className="col-xs-12">
<ul className="meta">
{fetchStatus}{projectInfo} <li>{reanalyzeButton}</li>
</ul>
<ul className="tags hidden-xs">
{tagList}
</ul>
</div>
</div>
You need to specify a getInitialState method in order to set the initial state. See here: https://reactjs.org/docs/react-without-es6.html#setting-the-initial-state
How do i set a state from a dynamically created p tag? The value i am trying to get is a mongodb id which is in the singleClass.id.How would i be able to set that id value as state for each iteration.So when button is clicked it goes to registerClass iam getting courseID.I used handleCourse but its not working for me please help.
handleCourse = e => {
e.preventDefault();
this.setState({
courseID: e.target.value
});
};
<ul className="collection with-header" key={singleClass.id}>
<li className="collection-item">
<div>
<p value={this.state.courseID} onChange={this.handleCourse}>
{singleClass.courseID}
</p>
<span>{singleClass.courseName}</span>
<div className="secondary-content">
<button
style={btnColor}
onClick={this.registerClass}
className="btn btn-flat"
type="button"
>
Enroll
</button>
</div>
</div>
</li>
</ul>
I'm starting with AngularJS and I am using a controller variable to navigate an array of questions, and it is working when using nextQuestion function, index gets updated and the next question is shown in the view, but if I try to obtain the same value (index) in a different function, it always returns 0.
I have seen on other questions that you should use an object to contain the variable to not manipulate primitive types directly in the controller, but it still does not work.
My controller:
myApp.controller('SurveyController',['$scope','$http', '$location','$routeParams','surveyMetrics','DataService',function($scope,$http, $location,$routeParams,surveyMetrics,DataService){
console.log('LOADED QUIZ CONTROLLER');
var vm = this;
vm.scope = {
index: 0
};
vm.surveyMetrics = surveyMetrics;
vm.surveyQuestions = DataService.surveyQuestions;
vm.DataService = DataService;
/*
vm.getQuestions = function(){
$http.get('/api/questions').then(function(response){
$scope.questions = response.data;
});
}
*/
/*
vm.activateSurvey = function(){
surveyMetrics.changeState(true);
}
*/
vm.getCurrentIndex = function(){
return vm.scope.index;
}
vm.nextQuestion = function () {
console.log('NEXT QUESTION!');
console.log('NUMBER OF QUESTIONS: '+ vm.surveyQuestions.length);
var currentIndex = vm.getCurrentIndex();
var newIndex = currentIndex+1;
scope = {};
if (currentIndex == vm.surveyQuestions.length) {
newIndex = vm.surveyQuestions.length -1;
}
vm.scope.index = newIndex;
console.log('Inside Object: '+vm.scope)
console.log('vm.index'+vm.scope.index);
console.log('vm.indexFunction'+vm.getCurrentIndex());
}
/*
vm.previousQuestion = function () {
console.log('PREVIOUS QUESTION!');
console.log('NUMBER OF QUESTIONS: '+ vm.surveyQuestions.length);
if (vm.scope.index == 0) {
vm.scope.index = 0;
}else{
vm.scope.index--;
}
}
*/
vm.activeSurveyQuestion = function(questionId,index){
console.log('question id and index',questionId,index);
if (questionId == index) {
var navBtn = document.getElementById('navBtn_'+index);
navBtn.classList.add('active');
}
}
vm.navigateSurvey = function () {
var answerPane = document.getElementById('answer-pane');
document.onkeydown = function (e) {
console.log('INSIDE KEYDOWN: ')
e.preventDefault();
var pressedKey = e.keyCode;
console.log('PRESSED KEY IN SURVEY: ' + pressedKey);
if (pressedKey === rightArrow) {
console.log('survey - right arrow pressed');
document.getElementById('nextQuestionBtn').click();
console.log('FUCKING INDEX FML!: '+vm.getCurrentIndex()+' | '+vm.scope.index);
var questionType = DataService.getQuestionType(vm.scope.index);
console.log('Survey Controller: question type: '+questionType);
}
if (pressedKey === leftArrow) {
console.log('survey - left arrow pressed');
document.getElementById('previousQuestionBtn').click();
}
(...)
My View:
<!--Satisfaction Survey-->
<div ng-controller="SurveyController as survey" ng-init="survey.getSurvey();">
<!--
<p ng-repeat="question in survey.surveyQuestions" ng-show ="survey.surveyMetrics.surveyActive">
{{question.question}}
</p>
-->
<!--Survey Modal -->
<div class="modal fade" id="surveyModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="text-center"> Customer Satisfaction Survey</div>
<div class="modal-header">
<h4 class="modal-title">{{survey.surveyQuestions[survey.getCurrentIndex()].question}}</h4>
</div>
<div class="modal-body survey" id="answer-pane">
<div class="row">
<div class="col-sm-2 survey-left-arrow" ng-click="survey.previousQuestion();" id="previousQuestionBtn">
<p>‹</p>
</div>
<div class="col-sm-8">
<!-- <p ng-repeat="answer in survey.surveyQuestions[survey.index].answers">{{answer}}</p> -->
<p ng-repeat="answer in survey.surveyQuestions[survey.getCurrentIndex()].answers">
<button type="button" class="btn" id="answerId_{{survey.getCurrentIndex()}}"
ng-class="{'survey-check-box': (survey.surveyQuestions[survey.getCurrentIndex()].type !== 'SingleChoice'),
'survey-btn_{{($index+1)}}': (survey.surveyQuestions[survey.getCurrentIndex()].type === 'SingleChoice')}">
<input type="checkbox" ng-if="survey.surveyQuestions[survey.getCurrentIndex()].type !== 'SingleChoice'"> {{answer}}
</button>
</p>
</div>
<div class="col-sm-2 survey-right-arrow " ng-click="survey.nextQuestion();" id="nextQuestionBtn">
<p>›</p>
</div>
</div>
</div>
<div class="text-center">
<strong> <p>Question: {{survey.surveyQuestions[survey.scope.index].questionNum}} of {{survey.surveyQuestions.length}}</p> </strong>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
<!-- <nav aria-label="Survey navigation">
<ul class="pagination pagination-sm justify-content-center">
<div ng-repeat="question in survey.surveyQuestions" >
<li class="page-item">
<a class="page-link" id = "navBtn_$index" ng-click="survey.index = $index">{{question.id}}</a>
</li>
</div>
</ul>
</nav> -->
</div>
</div>
I would like for the controller to change the variable and the view to update accordingly
Thank you for your time and thank you in advance.
It's 'survey.scope.index' not 'survey.index' in your HTML. I think you may be unclear the difference between using 'this' and '$scope'. You're mixing the two together which is not necessary. I would suggest removing 'scope' and just reference it in your HTML as 'survey.index'.