I have a multi step form using bootstrap and jQuery. The multi step form is for a user to buy a product. There are 4 steps: - Step 1 is for the user insert his info (name, email, etc) - Step 2 the user select the payment method - Step 3 the user introduces the payment data - Step 4 present an invoice for the user.
When the user click "go to step 2" the url changes to "store.test/product/5/a-5/payment/paymentMethods" and the user remains in the same payment page, but how to change from step 1 to step 2 in the multi step form?
The step1 html is like this:
<div class="tab-pane fade show active clearfix" id="step1" role="tabpanel" aria-labelledby="home-tab">
<h6>User Info</h6>
<form method="post" action="{{route('products.storeUserInfo', ['id' => $id, 'slug' => $slug])}}">
{{csrf_field()}}
<div class="form-group font-size-sm">
<label for="name" class="text-gray">Name</label>
<input type="text" required class="form-control" value="{{ (\Auth::check()) ? Auth::user()->name : old('name')}}">
</div>
<!-- other form fields -->
<input type="submit" href="#step2"
class="btn btn-primary btn float-right next-step" value="Go to step 2"/>
</form>
</div>
In paymentcontroller I have the storeUserInfo to collect the user data introduced in step1 and redirect to the same page (My doubt is how to redirect to the same page but show the step2 div):
public function storeUserInfo(Request $request, $id, $slug = null){
//dd($request);
$request->validate([
'name' => 'required|max:255|string',
'surname' => 'required|max:255|string',
'email' => 'required|max:255|string',
]);
Session::put('name' , $request->name);
Session::put('surname' , $request->surname);
Session::put('email' , $request->email);
return redirect(route('products.presentPaymentMethods',['id' => $id, 'slug' => $slug]));
}
public function presentPaymentMethods(Request $request, $id, $slug=null){
$productQuantities = Session::get('productQuantities');
return view('products.registration',
['productQuantities' => $productQuantities, 'id' => $id, 'slug' => $slug]);
}
Routes:
Route::post('/product/{id}/{slug?}/payment/storeUserInfo', [
'uses' => 'PaymentController@storeUserInfo',
'as' =>'products.storeUserInfo'
]);
Route::get('/product/{id}/{slug?}/payment/paymentMethods', [
'uses' => 'PaymentController@presentPaymentMethods',
'as' => 'products.presentPaymentMethods'
]);
jQuery to navigatte between steps:
<script type="text/javascript">
$(function(){
$('a.nav-link').on('show.bs.tab', function(e) {
var $target = $(e.target);
if (!divValid($('.nav-pills li a.active').prop('hash'))) {
e.preventDefault();
} else
if ($target.parent().hasClass('disabled')) {
e.preventDefault();
}
});
$(".next-step").click(function(e) {
var $active = $('.nav-pills li a.active');
nextTab($active);
});
$(".prev-step").click(function(e) {
var $active = $('.nav-pills li a.active');
prevTab($active);
});
function nextTab(elem) {
elem.parent().next().removeClass('disabled').find('a.nav-link').click();
}
function prevTab(elem) {
elem.parent().prev().find('a.nav-link').click();
}
});
Why don't you just collect all the data with js and post all at once to the server, I feel like you are going about this in a really complex way.
Alternatively, collect your data for step one, post to server redirect the user to step 2, and repeat.
e.g.
Route::get('step1', 'step3@PaymentController')->name('step1');
Route::post('step1store', 'step1@PaymentController')->name('step1-store');
Route::get('step2', 'step2@PaymentController')->name('step2');
Route::post('step2store', 'step2@PaymentController')->name('step2-store');
Route::get('step3', 'step3@PaymentController')->name('step3');
Route::post('step3store', 'step3@PaymentController')->name('step3-store');
public function step1store(Request $request)
{
//process your data and store to db
return redirect()->route('step2');
}
public function step2store(Request $request)
{
//process your data and store to db
return redirect()->route('step3');
}
public function step3store(Request $request)
{
//process your data and store to db
return redirect()->route('step4');
}
I'm sure you get the idea. Personally, I would go with posting all the data at once verifying each page with ajax.
I think this is what you are looking for
$(function(){
$('.next_step').click(function(){
var tab = $(this).attr('data-nexttab');
$('.tabs').hide().removeClass('show').addClass('hide');
$(tab).show().removeClass('hide').addClass('show');
});
});
.hide{
display:none;
}
.show{
display:block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="tabs show" id="tabs1">
Continue Here
<button type="button" data-nexttab="#tabs2" class="next_step">next</button>
</div>
<div class="tabs hide" id="tabs2">
Continue Here 2
<button type="button" data-nexttab="#tabs3" class="next_step">next</button>
</div>
<div class="tabs hide" id="tabs3">
Continue Here 3
<button type="submit" class="next_step">finish</button>
</div>
</div>