Bootstrap navbar drop down login in the React way - css

I am building a login feature into a bootstrap navbar, and using the boostrap dropdown component. By default, this component closes on a click. To handle login errors, however, the component needs to stay open to display an error message. Through JQuery, it's possible to either prevent the close and then show the desired error message. But this doesn't feel right in React.
But what is the right way to do this in React? It seems that, if there's a login error, I want to
1) Set a set a state variable with the correct error message
2) Call setState to force a re-render
3) On re-render, show the drop-down as open and with the error message
But how can I show the drop-down as open on the re-render? Is there a property that will force it to start opened? Below is the HTML
<li>
<a id="nav-login" className="nav-link dropdown-toggle" href="#" data-toggle="dropdown">Login</a>
<div className="useraccount-dropdown-menu dropdown-menu" onClick={this.preventClose} >
<p className="title">LOG IN</p>
<form action="#" onSubmit={this.login} method="post" acceptCharset="UTF-8">
<label>USER NAME</label>
<input className="textfield" ref="username" placeholder="userone#email.com" type="text"/>
<label>PASSWORD</label>
<input className="textfield" ref="password" placeholder="**********" type="password"/>
<button className="btn btn-primary btn-nativelogin" type="submit">Sign in</button>
</form>
</div>
</li>
Right now, onSubmit, the following function gets sets the error message - and calls setState. This is changing the state variable, but bootstrap closes the component so the re-render never happens.
login : function(e){
e.preventDefault();
Meteor.loginWithPassword(this.refs.username.value, this.refs.password.value, (error) => {
if(error){
this.setState({errorMsg: error.reason});
}else{
this.setState({isLoggedIn: true});
}
});
},
How can I prevent the component from closing? I tried adding an onClick event listener to the overall drop-down component and that calls stopPropagation.
preventClose: function(e){
e.preventDefault();
e.stopPropagation();
},
But this is not preventing the close.

You can handle the click event. Check out this demo
$('#myDropdown .dropdown-menu').on({
"click":function(e){
e.stopPropagation();
}
});
I hope this helps.

Related

Materialize css modal validation

I am using Materialize css to design my post. Suppose I have a form in modal and I and post it to server.
In that form I am checking if all fields are having value.
<form>
<div class="input-field">
<input type="text" id="title" class="validate" required="" aria-required="true">
<label for="title">Title</label>
</div>
The title field is required. But when I click on a submit button in modal it is closing even if title field has empty value. Is there any way to keep the modal open for validation error in Materialize css v1.
Think about this is in separate steps. The form submission only takes place at the end of the chain, when our criteria have been met.
User Submits form
We check the form
We feedback to user
Depending on the results of 2, we may either go back to step 1, or on to step 3.
Modal Structure:
<div id="modal1" class="modal">
<div class="modal-content">
<div class="input-field">
<input type="text" id="title" class="validate" required="" aria-required="true">
<label for="title">Title</label>
<span class="helper-text" data-error="Please enter your name" data-success="Thankyou!"></span>
</div>
</div>
<div class="modal-footer">
<a id="submit-button" href="#!" class="btn">Submit</a>
close
</div>
</div>
We add optional helper-text span for user feedback, as per the documentation.
The Javascript:
document.addEventListener('DOMContentLoaded', function() {
// init modal
var elems = document.querySelectorAll('.modal');
var instances = M.Modal.init(elems);
// get button
var button = document.querySelector('#submit-button');
// Run our own function when clicked
button.addEventListener("click", checkForm);
// Function checks for input
function checkForm() {
var input = document.querySelector('#title');
if(input.value) {
// submit form
// add valid class to show helper
input.classList.add('valid');
// close modal
instances[0].close();
// clear form
input.value = '';
// remove valid class
input.classList.remove('valid');
} else {
// prompt user for input
input.classList.add('invalid');
}
}
});
We grab the value of the text input, and based on that, add a valid or invalid class - this is the built in materialize stuff that hides or shows the relevant message that we set in data-error and data-success.
The only thing you need to add to this is the actual form submission - so something like form.submit().
Codepen.

Angular Material Slide Toggle not changing bound variable

I have 2 strange problems. I have a large form with lots of input fields. That works fine. I want to add a slide toggle at the bottom which changes a variable that will affect styles on the whole form.
My first problem is that the variable will not display until the slide toggle is clicked.
HTML
<mat-slide-toggle [(ngModel)]="ifPrint" name="ifPrint" id="ifPrint" ></mat-slide-toggle>
<div>
{{ifPrint}}
</div>
COMPONENT
export class PrintReviewDetailsComponent implements OnInit {
ifPrint = true;
}
the ifPrint variable is blank on page load
The second problem is
when the slide toggle is clicked the div containing the variable shows as true but when I click the toggle to the off position the ifPrint variable stays as true and does not change.
I have created a blitz and it is working fine there with the same code so I am unsure as why I am having these issues on my page.
The console says:
Error: No value accessor for form control with name: 'ifPrint'
EDIT: I updated the stackblitz to include the html of the form and now it is not working.
Your updated stackblitz couldn't recreate the issue which you shared... But from your question, the following 2 issues are addressed for a form and styling is also done:
the toggle value was not displayed by-default until the toggle was clicked
the toggle value didn't change when you toggled it
the style is now being updated based on the toggle value
relevant TS:
model:any;
constructor(){
this.model = {name: '' , age: null, ifPrint: false};
}
relevant HTML:
<form (ngSubmit)="formSubmit()" #demoForm="ngForm" >
<div [ngClass]="model.ifPrint === true ? 'trueClass' : 'falseClass'">
<input type="text" placeholder="Enter Name" #name="ngModel" [(ngModel)]="model.name" name="name" />
<br/>
<input type="number" placeholder="Enter Age" #age="ngModel" [(ngModel)]="model.age" name="age" /> <br/>
<mat-slide-toggle #ifPrint #age="ngModel" [(ngModel)]="model.ifPrint" name="ifPrint"></mat-slide-toggle> {{model.ifPrint}} <br/>
</div>
<button type="submit"> Submit </button>
</form>
check a minimal, working demo here for what you're trying... hope it helps...
I removed everything in your template except the mat-slide-toggle and it works as expected.
I believe the issue is because your html template is referencing methods or properties that your component does not have, or trying to access a property of null or undefined somewhere is causing the issue.
Check your console for the errors and if you fix those up, the slide toggle should work as expected.

How to focus input element in html in React popup behaviour

I have a React Typescript app and when the user clicks a button, they should be prompted with a model dialog that asks them for a comment. I would like the textbox input control of this modal to be focussed when they click the button, so they can start typing straight away - but can't figure out how to do that. Can anyone suggest?
Also as a second question - is there a way I can bind the "Enter" keystroke to close the modal? Escape is built in as a special behaviour character in NPM react-modal but I would like Enter to submit the OK button.
My react modal component (using NPM react-modal)
<ReactModal
isOpen={this.state.dialogOpen}
contentLabel="Example Modal"
className="Modal"
overlayClassName="Overlay"
shouldCloseOnEsc={true}
shouldReturnFocusAfterClose={true}
role="dialog"
onRequestClose={this.handleCloseModal}
shouldCloseOnOverlayClick={false}
// tslint:disable
parentSelector={() => document.body}
>
<div className="Modal-Container">
<div style={{flex:0.4}}>
<div className="Panel-header-left">
Please enter a reason for rejecting
</div>
</div>
<div style={{flex:0.6}}>
<input type="textbox" name="ModalInput" value={this.state.comment} onChange={ this.handleCommentChange.bind(this)} />
</div>
<div>
<div className="Panel-header-right">
<button className="Action-Button" onClick={(e) => this.handleCloseModal()}>Cancel</button>
<button className="Action-Button" onClick={(e) => this.processRejectComments()}>OK</button>
</div>
</div>
</div>
</ReactModal>
and my button click to load the modal
private doReject()
{
if (this.gridApi.getSelectedNodes().length > 0)
{
this.setState({comment: ""});
this.handleOpenModal();
}
}
1. To focus the input of the modal, first set reference of <input> then call input.focus() in onAfterOpen() of react-modal
<ReactModal
isOpen={this.state.dialogOpen}
onAfterOpen={() => this._input.focus()}
>
<input ref={input => this._input = input}/>
</ReactModal>
2. To close modal on user press Enter, wrap the <input> by a <form>, then close model in its onSubmit()
<ReactModal
isOpen={this.state.dialogOpen}
>
<form onSubmit={() => this.setState({dialogOpen: false})>
<input {...} />
</form>
</ReactModal>
Here's CodeSandbox: https://codesandbox.io/s/wn18lvjlx7

Can helpers detect new elements created by createElement()?

I have a page with table. Each table row, has two links "delete", and "edit". "delete" works fine.
I would like to do this scenario:
When user clicks on row "edit" link, a small window appears with the fields of this row.
User decide to edit or not.
User may press "Save Changes", or "Cancel".
I did the option of small window with JavaScript document.createElement(), and the window appears successfully.
But I would like to add helpers for "Save Changes", and "Cancel" buttons.
I can't do this using helpers
Template.codesList.events({
'submit form#newForm': function (events) {
// some actions
};
},
'click #edit': function () {
var px = 'px';
// Create an Overlay
var myOverlay = createOverlay();
document.body.appendChild(myOverlay);
// Create edit window display it over the Overlay
var editWindow = createPopup(300, 400);
// Create elements and append it to edit window
var editForm = editWindowForm(this._id, this.name);
editWindow.appendChild(editForm);
document.body.appendChild(editWindow);
},
'click #delete': function () {
if (confirm("Are you sure?")) {
Codes.remove({_id: this._id})
}
},
'submit form#editForm': function (event) {
event.preventDefault();
console.log("Clicked"); // This doesn't displayed
}
});
And this is the form after displaying it.
<form id="editForm" style="margin-right: 3em; margin-left: 3em;">
<div class="form-group">
<label for="itemCode" class="control-label">Code</label>
<input id="itemCode" name="itemCode" class="form-control" placeholder="Enter code">
</div>
<div class="form-group">
<label for="itemName" class="control-label">Name</label>
<input id="itemName" name="itemName" class="form-control" placeholder="Enter name">
</div>
<input type="submit" value="Save Changes" class="btn btn-primary">
<input type="button" value="Cancel" class="btn btn-info">
</form>
But when I press on "Save Changes" button, no print from console.log() and the form is making the normal submit and the page reloads again.
So, what I'm missing?
By the way that's the output of the console:
document.querySelector('form#editForm')
<form id=​"editForm" style=​"margin-right:​ 3em;​ margin-left:​ 3em;​">​…​</form>​
Define edit form as a template. Use event handlers as usual to handle save and cancel button clicks.
To render it, either just put it inside the page template with '#if sessionEditPopup' or if you must do it yourself then use UI.renderWithData docs here
BTW manually modifying DOM using jquery etc is something to be avoided unless there is no other way and is not the Meteor way of doing things.
Add event on click save the data into Session because Session can access globally.
And Take the data from Template.name.Healper using session,
So when u change the session value that will automatically change your page content.
Here is the link may be useful for U
http://meteortips.com/first-meteor-tutorial/sessions/

Add button to accordion heading angular-ui bootstrap

I'm trying to add a button on the accordion heading. but when I click on the button, the accordion group collapse or open. but i dont want to trigger the accordion click when I click on the button.
If i put the button tag inside accordion-heading, it will put that into accordion-toggle class. so it wont trigger the button click. not sure if there is an easy way to change it.
http://plnkr.co/edit/eXE7JjQTMxn4dOpD7uKc?p=preview
Anyone can help?
Thanks
Add $event.stopPropagation(); in the ng-click.
http://plnkr.co/edit/eXE7JjQTMxn4dOpD7uKc?p=preview
The check marked solution didn't work for me, until I added $event.preventDefault() before $event.stopPropagation(). Maybe I got different results because I'm dealing with a check box or a newer version of Angular?
<uib-accordion-heading>
{{ thisGroup.stringThatShouldOpenAndCloseTheHeader }}
<!-- my checkbox changes -->
<div class="material-switch pull-right">
<input type="checkbox" id="{{ thisGroup._id }}" name="{{ thisGroup._id }}" ng-checked="thisGroup.active" />
<label for="{{ thisGroup.template._id }}" ng-click="$event.preventDefault(); $event.stopPropagation(); $ctrl.checkOrUnCheck(arg)"></label>
</div>
</uib-accordion-heading>
I needed BOTH, though. If I removed either, any clicking on the checkbox would open or close the accordion
or you can create a directive in your button tag for further usage :
.directive('yourDirective',function(){
return{
restrict:'A',
link : function(scope,ele,attr){
ele.bind("click",function(event){
alert('I will not toggle accordion');
event.preventDefault();
event.stopPropagation();
})
}
}
})
HTML
<button your-directive> Click Me <button>

Resources