how to fix jQuery 'previous' button - html

The code below shows a multi step form, the second page displays two buttons next and previous and for some reason the previous button doesn't work. I tried playing with code a lot but I couldn't figure it out. Please help.
<form class="form-wrapper">
<fieldset class="section is-active">
<h3>Details</h3>
<div class="inputlabel">
<label>Exchange</label>
</div>
<input type="text" placeholder="Exchange..">
<div class="button">Next</div>
</fieldset>
<fieldset class="section">
<h3>Title</h3>
<div class="inputlabel">
<label>Balance</label>
</div>
<input type="text" placeholder="Password" readonly>
<div class="btnpre" onclick="prvbtn()" id="btnprevious">Previous</div>
<input class="submit button" type="submit" value="Finish">
</fieldset>
<fieldset class="section">
<i class="fas fa-check-circle fa-7x"></i>
<h2>Saved</h2>
<p>Your Data has been saved</p>
<div class="button" id="button2">Close</div>
</fieldset>
</form>
This is the jQuery script
<script>
$(document).ready(function(){
$(".form-wrapper .button").click(function(){
var button = $(this);
var currentSection = button.parents(".section");
var currentSectionIndex = currentSection.index();
var headerSection = $('.steps li').eq(currentSectionIndex);
currentSection.removeClass("is-active").next().addClass("is-active");
headerSection.removeClass("is-active").next().addClass("is-active");
$(".form-wrapper").submit(function(e) {
e.preventDefault();
});
function prvbtn(){
if(currentSectionIndex === 1){
currentSectionIndex = 0;
}
if(currentSectionIndex === 2){
$(document).find(".form-wrapper .section").first().addClass("is-active");
$(document).find(".steps li").first().addClass("is-active");
}
});
});
</script>

Consider the following example.
$(function() {
// Define a Global Index
var sectionIndex = 0;
$(".form-wrapper .button").click(function() {
// Examine the button and determine which button was clicked
if ($(this).hasClass("next")) {
// Use the current Index and them increment it
$(".section").eq(sectionIndex++).toggleClass("is-active");
$(".section").eq(sectionIndex).toggleClass("is-active");
} else {
// Use the current Index and them decrement it
$(".section").eq(sectionIndex--).toggleClass("is-active");
$(".section").eq(sectionIndex).toggleClass("is-active");
}
});
$(".form-wrapper").submit(function(e) {
e.preventDefault();
});
});
.section {
display: none;
}
.section.is-active {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form class="form-wrapper">
<fieldset class="section is-active">
<h3>Details</h3>
<div class="inputlabel">
<label>Exchange</label>
</div>
<input type="text" placeholder="Exchange..">
<div class="next button">Next</div>
</fieldset>
<fieldset class="section">
<h3>Title</h3>
<div class="inputlabel">
<label>Balance</label>
</div>
<input type="text" placeholder="Password" readonly>
<div class="previous button" id="btnprevious">Previous</div>
<input class="submit button" type="submit" value="Finish">
</fieldset>
<fieldset class="section">
<i class="fas fa-check-circle fa-7x"></i>
<h2>Saved</h2>
<p>Your Data has been saved</p>
<div class="button" id="button2">Close</div>
</fieldset>
</form>
This assigns one callback to all button elements. With an if statement, we can easily determine the direction.

Related

How to change name attributes for auto added inputs and textareas?

I'm trying to create a cv creater form and need to let users add more inputs (auto).
I created inputs and they work just fine, but I need to change the name attribute for each auto added block.
For example :
<input type="text" id="fname" name="fname">
<input type="text" id="fname" name="fname2">
<input type="text" id="fname" name="fname3">
I know I can use name="value[]" array, but every new block goes into a different column in the database, so I need to change attributes.
My code :
$(document).ready(function() {
var max_fields = 10;
var wrapper = $("#contant");
var add_button = $("#add_form_field");
var x = 1;
$(add_button).click(function(e) {
e.preventDefault();
if (x < max_fields) {
x++;
$(wrapper).append('<div id="input-social" class="input-container"><input type="text" id="social" class="col-11 form-control" name="fname" placeholder="fname"> <span id="deleteInput" class="AutoInput" title="Delete"><i class="fas fa-trash-alt"></i></span></div>');
} else {
alert('You Riched limit.')
}
});
$(wrapper).on("click", "#deleteInput", function(e) {
e.preventDefault();
$(this).parent('#input-social').remove();
x--;
})
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://kit.fontawesome.com/e794a0f8b4.js" crossorigin="anonymous"></script>
<div class="form-group">
<div class="row">
<label class="col-3 inputFontSize" for="social">Others</label>
<div id="contant" class="col-7">
<button id="add_form_field" class="btn add_form_field">Add more <i class="fas fa-plus"></i></button>
</div>
<!-- col-9 -->
</div>
<!-- row -->
</div>
<!-- form-group -->
Thanks for all helps
You can use your x variable that is incremented for each added input and append it to the name attribute. We'll use a 'template string'. The adjustment is name="fname${x}" which will substitute ${x} for the value of x.
$(wrapper).append(`
<div id="input-social" class="input-container">
<input type="text" id="social" class="col-11 form-control" name="fname${x}" placeholder="fname">
<span id="deleteInput" class="AutoInput" title="Delete">
<i class="fas fa-trash-alt"></i>
</span>
</div>`
);
$(document).ready(function() {
var max_fields = 10;
var wrapper = $("#contant");
var add_button = $("#add_form_field");
var x = 1;
$(add_button).click(function(e) {
e.preventDefault();
if (x < max_fields) {
x++;
$(wrapper).append(`<div id="input-social" class="input-container"><input type="text" id="social" class="col-11 form-control" name="fname${x}" placeholder="fname"> <span id="deleteInput" class="AutoInput" title="Delete"><i class="fas fa-trash-alt"></i></span></div>`);
} else {
alert('You Riched limit.')
}
});
$(wrapper).on("click", "#deleteInput", function(e) {
e.preventDefault();
$(this).parent('#input-social').remove();
x--;
})
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://kit.fontawesome.com/e794a0f8b4.js" crossorigin="anonymous"></script>
<div class="form-group">
<div class="row">
<label class="col-3 inputFontSize" for="social">Others</label>
<div id="contant" class="col-7">
<button id="add_form_field" class="btn add_form_field">Add more <i class="fas fa-plus"></i></button>
</div>
<!-- col-9 -->
</div>
<!-- row -->
</div>
<!-- form-group -->

Show element with input button only with css

I want to show an section when the checkbox is checked on another section, and show it with an animation from the top. I have the following code for the input that is in another section .
<div className="continue" id="first">
<button className="btn-continue">
Contratar Plano
<input type="checkbox" id="reveal-email" role="button"/>
</button>
</div>
<section className="plan-section" id="plan-section">
<div className="next">
<i class="arrow down"></i>
</div>
<div className="form-block">
<form className="form">
<div className="plan-form">
<div className="input-block">
<label htmlFor="name">Nome</label>
<input type="text" name="name" id="name" onChange={props.handleChange} required className="input" />
</div>
<div className="continue">
<button className="btn-continue" id="plan-continue" disabled={props.step.isLast()} onClick={props.next}>
<span className="btn-text">Contratar Plano</span>
<img className="check-btn" src={check} />
</button>
</div>
</div>
</form>
</div>
</section>
Also showing the section I need to show; this section has a default display:none.
Its a classic JS task. Use an onclick event to check if the checkbox is checked and then to change the section from display: none to display: block . Also Add an onclick event so that JS is triggered.
function showSection() {
var showSection = document.getElementById("reveal-email"),
planSection = document.getElementById("plan-section");
if (showSection.checked == true) {
planSection.style.display = "block";
} else {
planSection.style.display = "none";
}
}
#plan-section {
display: none;
}
<div className="continue" id="first">
<button className="btn-continue">Contratar Plano
<input type="checkbox" id="reveal-email" onclick="showSection()">
</button>
</div>
<section className="plan-section" id="plan-section">
<div className="next">
<i class="arrow down"></i>
</div>
<div className="form-block">
<form className="form">
<div className="plan-form">
<div className="input-block">
<label htmlFor="name">Nome</label>
<input type="text" name="name" id="name" onChange={props.handleChange} required className="input" />
</div>
<div className="continue">
<button className="btn-continue" id="plan-continue" disabled={props.step.isLast()} onClick={props.next}>
<span className="btn-text">Contratar Plano</span>
<img className="check-btn" src={check} />
</button>
</div>
</div>
</form>
</div>
</section>
One recommendation regarding your code:
<button className="btn-continue">
Contratar Plano
<input type="checkbox" id="reveal-email" role="button"></input>
</button>
It's not a good practice to group checkbox and some text into button, in HTML you can use label for that.
If JS solution is acceptable, you need to follow these steps:
Find your checkbox button and section in the DOM
Add event listener which will trigger callback function after each change of the checkbox state
In the callback function you need to trigger style for your section.
The full code is below:
var checkbox = document.getElementById('reveal-email');
var section = document.getElementById('plan-section');
checkbox.addEventListener('change', onChange)
function onChange() {
if (this.checked) {
section.style.display = "block";
} else {
section.style.display = "none";
}
}
<div className="continue" id="first">
<button className="btn-continue">
Contratar Plano
<input type="checkbox" id="reveal-email" role="button"/>
</button>
</div>
<section className="plan-section" id="plan-section" style="display:none">
<div className="next">
<i class="arrow down"></i>
</div>
<div className="form-block">
<form className="form">
<div className="plan-form">
<div className="input-block">
<label htmlFor="name">Nome</label>
<input type="text" name="name" id="name" onChange={props.handleChange} required className="input" />
</div>
<div className="continue">
<button className="btn-continue" id="plan-continue" disabled={props.step.isLast()} onClick={props.next}>
<span className="btn-text">Contratar Plano</span>
<img className="check-btn" src={check} />
</button>
</div>
</div>
</form>
</div>
</section>

Button alignment relative to button inside of another controller

I have two buttons inside separate controllers.
<div ng-controller="aCtrl">
<button class="addButton" ng-click="toggle()"> Add </button>
<form ng-hide="myVar" ng-submit="submit()">
<input ......
<input ......
</form>
</div>
<div ng-controller="bCtrl">
<button class="EditButton" ng-click="toggle()"> Add </button>
<form ng-hide="myVar" ng-submit="submit()">
<input ......
<input ......
</form>
</div>
Note: Toggle just switches the hide/show bool in the back-end
As you can see when clicking the Addbutton it will show the form for aCtrl and EditButton for bCtrl. The result of the current layout is when Add Buttons form expands it pushes the EditButton down. I don't think this can be fixed with CSS as its the logical flow of the HTML.
I am looking for solutions that would allow me to have the buttons at the top in the flow of the page then the forms below.
for example I tried:
<button ng-controller="aCtrl" class="EditButton" ng-click="toggle()"> Add </button>
<button ng-controller="bCtrl" class="addButton" ng-click="toggle()"> Add </button>
<div ng-controller="aCtrl">
<form ng-hide="myVar" ng-submit="submit()">
<input ......
<input ......
</form>
</div>
<div ng-controller="bCtrl">
<form ng-hide="myVar" ng-submit="submit()">
<input ......
<input ......
</form>
</div>
Which doesn't seem to work.
The problem is that ng-hide hides the content with a display: none that causes the space occupied by the element to collapse.
You need visibility: hidden that also hides the element, but keeps the space.
Therefore, use ng-class instead of ng-hide:
<div ng-controller="aCtrl">
<button class="addButton" ng-click="toggle()"> Add </button>
<form ng-class="{ 'hidden' : myVar }" ng-submit="submit()">
<input ......
<input ......
</form>
</div>
<div ng-controller="bCtrl">
<button class="EditButton" ng-click="toggle()"> Add </button>
<form ng-class="{ 'hidden' : myVar }" ng-submit="submit()">
<input ......
<input ......
</form>
</div>
and the CSS
.hidden {
visibility: hidden;
}
Here is a live sample:
var myApp = angular.module('myApp',[]);
function aCtrl($scope) {
$scope.myVar = true;
$scope.toggle = function () {
$scope.myVar = !$scope.myVar;
}
}
function bCtrl($scope) {
$scope.myVar = true;
$scope.toggle = function () {
$scope.myVar = !$scope.myVar;
}
}
.hidden {
visibility: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<section ng-app="myApp">
<div ng-controller="aCtrl">
<button class="addButton" ng-click="toggle()"> aCtrl.Add </button>
<form ng-class="{ 'hidden' : myVar }" ng-submit="submit()">
<input type="text" value="aCtrl.form">
</form>
</div>
<div ng-controller="bCtrl">
<button class="EditButton" ng-click="toggle()"> bCtrl.Add </button>
<form ng-class="{ 'hidden' : myVar }" ng-submit="submit()">
<input type="text" value="bCtrl.form">
</form>
</div>
</section>
As you can see, the bCtrl.Add button remains in place, regardless whether aCtrl.form is visible or not.
It can be done via css only, just wrap the two in a div with position: relative and then add position:absolute to addButton and editButton together with top/left/right positioning values.
<div class="formContainer">
<div ng-controller="aCtrl">
<button class="addButton" ng-click="toggle()"> Add </button>
<form ng-hide="myVar" ng-submit="submit()">
<h1>Add form</h1>
<input type="text">
<input type="text">
</form>
</div>
<div ng-controller="bCtrl">
<button class="editButton" ng-click="toggle()"> Edit </button>
<form ng-hide="myVar" ng-submit="submit()">
<h1>Edit form</h1>
<input type="text">
<input type="text">
</form>
</div>
</div>
and css:
.formContainer {
position: relative;
width: 200px;
padding-top: 30px;
}
.addButton {
position: absolute;
top: 0;
right: 40px;
}
.editButton {
position: absolute;
top: 0;
right: 0;
}
Here's a working demo: Plunker CSS Only
There's another way, put them in a parent controller, which would hold the logic for toggling between the forms and then each form have their own controller for their respective functionalities.
Here's a working demo of the second version: Plunker with parent Controller
Here is example as u mentioned in your post. u can keep button outside of your controllers
var myApp = angular.module('myApp',[]);
myApp.controller('aCtrl', ['$scope', function ($scope) {
$scope.myVar = true
}]);
myApp.controller('bCtrl', ['$scope', function ($scope) {
$scope.myVar = true;
}]);
function getscope(ctrlName) {
var sel = 'div[ng-controller="' + ctrlName + '"]';
return angular.element(sel).scope();
}
function showForm(ctrlName) {
var $scope = getscope(ctrlName);
$scope.myVar = !$scope.myVar;
$scope.$apply();
}
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
<section ng-app="myApp">
<button class="addButton" onclick="showForm('aCtrl')"> aCtrl.Add </button>
<button class="EditButton" onclick="showForm('bCtrl')"> bCtrl.Add </button>
<div ng-controller="aCtrl">
<form ng-hide="myVar" ng-submit="submit()">
<input type="text" value="aCtrl.form">
</form>
</div>
<div ng-controller="bCtrl">
<form ng-hide="myVar" ng-submit="submit()">
<input type="text" value="bCtrl.form">
</form>
</div>
</section>
Is having two controllers is your requirement ?
You can have a separate controller of the button for eg. btnCtrl and toogle the value using a $rootscope variable. As follows.
<button ng-controller="btnCtrl" class="EditButton" ng-click="toggle()"> Add </button>
<button ng-controller="btnCtrl" class="addButton" ng-click="toggle()"> Add </button>
<div ng-controller="aCtrl">
<form ng-hide="$root.myVar" ng-submit="submit()">
<input ......
<input ......
</form>
</div>
<div ng-controller="bCtrl">
<form ng-hide="$root.myVar" ng-submit="submit()">
<input ......
<input ......
</form>
</div>

knockout does not change the radio button view

I have a working panel with radio buttons a label and a textfield. Everything works good except if i click on radio buttons explicitly the radio button does not change the radio button view.
Here the plnkr link to it:
https://embed.plnkr.co/auD0sMEL88EsuaQqvt7E/
As #user3297291 mention that the checked and click binding get in confict.
Add this binding:
ko.bindingHandlers.stopBubble = {
init: function(element) {
ko.utils.registerEventHandler(element, "click", function(event) {
event.cancelBubble = true;
if (event.stopPropagation) {
event.stopPropagation();
}
});
}
};
You have to add in every radio element this binding like this:
<input data-bind="checked: discountValue, stopBubble: true" id="discountArbitrary" name="discount" type="radio" value="arbitrary" />
I created one jsfiddle that works as you expected.
https://jsfiddle.net/astrapi69/s3r60uLu/
I guess the click binding is conflicting with checked binding.
You can use computeds to calculate enabled/focused flags.
You can check modified code (I've omitted focused flags in favor of simplicity):
// Code goes here
var DiscountViewModel = function() {
var self = this;
self.arbitrary = ko.observable();
self.percent = ko.observable();
self.permanent = ko.observable();
self.discountValue = ko.observable('arbitrary');
self.enableArbitrary = ko.computed(() => self.discountValue() === 'arbitrary');
self.enablePercent = ko.computed(() => self.discountValue() === 'percent');
self.enablePermanent = ko.computed(() => self.discountValue() === 'permanent');
self.onArbitrary = onArbitrary;
self.onPercent = onPercent;
self.onPermanent = onPermanent;
function onArbitrary() {
self.discountValue('arbitrary');
}
function onPercent() {
self.discountValue('percent');
}
function onPermanent() {
self.discountValue('permanent');
}
};
var vm = new DiscountViewModel();
ko.applyBindings(vm);
/* Styles go here */
.header-line {
margin-bottom:20px;
margin-top:20px;
margin-left:20px;
}
<script data-require="jquery#2.1.3" data-semver="2.1.3" src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.3.3/js/tether.js"></script>
<link data-require="bootstrap#4.0.0-alpha.2" data-semver="4.0.0-alpha.2" rel="stylesheet" href="https://cdn.rawgit.com/twbs/bootstrap/v4-dev/dist/css/bootstrap.css" />
<script data-require="bootstrap#4.0.0-alpha.2" data-semver="4.0.0-alpha.2" src="https://cdn.rawgit.com/twbs/bootstrap/v4-dev/dist/js/bootstrap.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-debug.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js" type="text/javascript" defer="defer"></script>
<h1 class="header-line">
KO binding hasFocus over boolean values
</h1>
<div class="form-group row">
<div class="col-xs-1">
</div>
<div class="col-xs-1">
<input name="discount" type="radio" value="arbitrary" data-bind="checked: discountValue" />
</div>
<div class="col-xs-4">
<label for="arbitrary" data-bind="click: onArbitrary">Discount arbitrary</label>
</div>
<div class="col-xs-5">
<input type="text" class="form-control" id="arbitrary" placeholder="Enter arbitrary discount" data-bind="enable: enableArbitrary, value: arbitrary, hasFocus: enableArbitrary">
</div>
</div>
<div class="form-group row">
<div class="col-xs-1">
</div>
<div class="col-xs-1">
<input name="discount" type="radio" value="percent" data-bind="checked: discountValue" />
</div>
<div class="col-xs-4">
<label for="percent" data-bind="click: onPercent">Discount percent</label>
</div>
<div class="col-xs-5">
<input type="text" class="form-control" id="percent" placeholder="Enter percent of discount" data-bind="enable: enablePercent, value: percent, hasFocus: enablePercent">
</div>
</div>
<div class="form-group row">
<div class="col-xs-1">
</div>
<div class="col-xs-1">
<input name="discount" type="radio" value="permanent" data-bind="checked: discountValue" />
</div>
<div class="col-xs-4">
<label for="permanent" data-bind="click: onPermanent">Discount permanent</label>
</div>
<div class="col-xs-5">
<input type="text" class="form-control" id="permanent" placeholder="Enter permanent discount" data-bind="enable: enablePermanent, value: permanent, hasFocus: enablePermanent">
</div>
</div>
The problem is that by clicking the radio button, two things happen:
The checked binding does its thing
The event bubbles up to the parent element, and the click binding also does its thing.
You'll have to make sure clicking the input element stops the click binding from firing.
There's a great answer by R.P. Niemeyer here: https://stackoverflow.com/a/14321399/3297291

ReactJS <p/> or <br/> not working in render()

I can't get <p/> or <br/> to create new lines when used after a custom ReactJS component that uses this Bootstrap CSS in the form <div className="col-sm-10"> i.e.
var MyChatClientView = React.createClass({
render: function() {
return (
<div>
<h2>Chat</h2>
<span>Type something</span>
<MyChatForm />
<p/>
<br/>
<div>
This text is on the same line as MyChatForm, I want it on a new line!
</div>
</div>
);
}
});
var MyChatForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var myChatTxt = this.refs.myChatTxt.getDOMNode().value.trim();
},
render: function() {
return (
<div>
<form role="form" onSubmit={this.handleSubmit}>
<div className="form-group">
<input type="textarea" className="form-control" id="post-chat" ref="myChatTxt" />
</div>
<div className="form-group">
<div className="col-sm-10">
<button type="submit" className="btn btn-primary btn-lg btn-block">Send</button>
</div>
</div>
</form>
</div>
);
}
});
To size form controls using Bootstrap, either (1) your form needs the form-horizontal class or (2) your columns need to be wrapped in an element with the row class.
This is covered in the control sizing section of the Bootstrap docs.
In your case it seems to make sense to replace the form-group with the needed row:
var MyChatForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var myChatTxt = this.refs.myChatTxt.getDOMNode().value.trim();
},
render: function() {
return (
<div>
<form role="form" onSubmit={this.handleSubmit}>
<div className="form-group">
<input type="textarea" className="form-control" id="post-chat" ref="myChatTxt" />
</div>
<div className="row">
<div className="col-sm-10">
<button type="submit" className="btn btn-primary btn-lg btn-block">Send</button>
</div>
</div>
</form>
</div>
);
}
});