From submit in a AJAX-generated tabs (Twitter Bootstrap) - javascript

I'm trying to submit a from which is located into a tabs. This tabs content is generated via AJAX.
My problem is that when I submit the form, the page refresh and the "default" tab is loaded so the php function generating the tab with the form never receive the post data.
Here the solutions I though about :
1) The easiest : Finding a way to insert a hash in the URL so that when the page refresh, a javascript code load the good tab.
2) The best (considering user experience) : Finding a way to submit the form with ajax and add the new entry to the list under the form in the tab. BUT I want to use php to check form values (is_empty(), etc.). I thought about sending data to the php controller, then, hide the form and replace it with the new form generated by the php controller (with error messages or empty fields if fields were ok and data added to the DB).
Here is my code :
The layout :
<ul class="nav nav-tabs" id="myTabs">
<li class="active">Profile</li>
<li>About</li>
<li>Wishlists <span class="badge"><?= $profile['wishlists'] ?></span></li>
<li>Following <span class="badge"><?= $profile['following'] ?></span></li>
<li>Followers <span class="badge"><?= $profile['followers'] ?></span></li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane active" id="profile">Profile</div>
<div class="tab-pane" id="about">about</div>
<div class="tab-pane" id="wishlist">wl</div>
<div class="tab-pane" id="following">following</div>
<div class="tab-pane" id="followers">followers</div>
</div>
The tab :
<?php
if($owner)
{ ?>
<div class="row">
<div class="col-md-10 col-md-offset-1">
<form class="form-horizontal" role="form" method="post">
<fieldset><legend>Add a wishlist</legend>
<?php echo $form; ?>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default" name="addwishlist">Add</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
<hr />
<?php
}
?>
<div class="row">
<?php
foreach($wishlists as $wishlist)
{ //Here we display whislists } ?>
The php controller that corresponding to the tabs view :
$manager = $this->managers->getManagerOf('Wishlist');
/**
* Adding a new wishlist
*/
if($owner)
{
//Creating object. Depends on form validation
if ($request->postExists('addwishlist'))
{
$wishlist = new \Lib\Entities\Wishlist(array(
'title' => $request->postData('title'),
'comment' => $request->postData('comment'),
'user' => $this->app->user()->getUser(),
));
}
else
{
$wishlist = new \Lib\Entities\Wishlist;
}
//generating form
$formBuilder = new \Lib\Forms\WishlistForm($wishlist);
$formBuilder->build();
$form = $formBuilder->form();
$formHandler = new \Lib\FormHandler($form, $manager, $request);
//if form has been validate : add the wishlist and set flash
if ($formHandler->process('add'))
{
$this->app->user()->setFlash('Your wish list has been created !');
$this->app->httpResponse()->redirect('/Shawili/'.$request->getData('user').'/wishlists/');
}
$this->page->addVar('form', $form->createView());
}
/**
* Displaying user's wishlists
*/
$wishlists = $manager->getWishlists($request->getData('user'), $this->app->user()->getUser());
$this->page->addVar('wishlists', $wishlists);
$this->page->addVar('owner', $owner);
$this->page->addVar('profile', $request->getData('user'));
$this->page->addVar('cuser', $this->managers->getManagerOf('User')->getUser($this->app->user()->getUser()));
The Jquery code :
<script type='text/javascript'>
$('#myTabs a').click(function (e) {
e.preventDefault();
var url = $(this).attr("data-url");
var href = this.hash;
var pane = $(this);
// ajax load from data-url
$(href).load(url,function(result){
pane.tab('show');
});
});
// load first tab content
$('#profile').load($('.active a').attr("data-url"),function(result){
$('.active a').tab('show');
});
</script>
Any suggestion of the best way to do that?

Second option is rather widely used practice and it always works well, so you can use it without concern.
Looking at your code I suppose, that you want to generate form code and send it via ajax to browser. It is not necessarily best way to do it. You don't have to hide and replace form. You can easyly modify existing one with jQuery.
The trick is to send to the browser only formated data containing info about errors etc. (for example using JSON) and then decode it (jQuery way) and localy modify content of web page.
To submit form via ajax you can just overwrite click event for the button and then collect data from fields and send it to the server, for example like this:
$("#submit_button_id").click(function(){
var formdata = $("#form_id").serializeArray();
$.ajax({
url: "/submit_url",
data: formdata,
success: function(RESPONSE){
//Your code to modify page content after geting RESPONSE.
}
})
return false; //To prevent page from reloading
}

Related

Do #PostMapping and stay on page without redirect

I use Spring Boot.
There is a page where all ads are displayed. I need to add ads to favorites. This must be done without navigating to other pages or reloading the current page. So user can click on the button and scroll further, inside it has added to favorites. How can this be done without redirect?
I tried different variants and it doesn't work. Help me please!(
I know that I have to use js, but it doesn't work for me. Also I need to change the method addToFavorites. Can you change my code and show it clearly?
My HTML:
<div th:each="ad : ${page.getContent()}">
<div>
<div>
<p><a th:href="#{/advert/{id}(id=${ad.getId()})}" th:text="${ad.getHeadline()}">Headline</a></p>
<p th:text="${ad.getDescription()}">Description</p>
<p><i class="fa fa-map-marker" aria-hidden="true" th:text="${dao.getLocation(ad)}"></i> New York</p>
<p><i class="fa fa-clock-o" aria-hidden="true"></i><span th:text="${dao.getDate(ad)}">12.07.2020 19:08</span></p>
</div>
<form th:action="#{/favorites}" method="post">
<input type="hidden" name="ad" th:value="${ad}">
<button type="submit">Add to favorites</button>
</form>
</div>
</div>
My Java:
#GetMapping("/advert")
public String mainPage(#PageableDefault(sort = {"id"}, size = 10, direction = Sort.Direction.DESC) Pageable pageable,
Model model) {
Page<Advert> page = advertDAO.findAll(pageable);
model.addAttribute("page", page);
model.addAttribute("dao", advertDAO);
return "main";
}
#PostMapping("/favorites")
public void addToFavorites(#RequestParam("ad") Advert advert){
// add to favorites
}
To do POST call without redirecting, You can use ajax call on button click that will call your controller and give response also..
$.ajax({
type: "POST", // It can be GET also
url: "your_ulr",
success: function(response){
//if request if made successfully then the response represent the data
// Do here whatever you want
}
});

Dynamically loading content within a partial view

Basically, I am trying to implement tabs on a main page. The tabs will consist of components on other pages for quick access. I am confused on how I can import a layout while sending data to it in a "lazy" way.
I now use the #section tag to bring in the layout, which is fine. But I only want to request the data it needs when the tab is clicked.
in my main.blade.php:
<li>
<a href="#tab_1" data-controller="tab_1" data-target="#tab_1" data-toggle="tab" aria-expanded="true">
tab 1 </a>
</li>
<div class="tab-pane" id="tab_1" >
#yield('tab_1')
</div>
in my tab1:
#extends('main')
#section('tab_1')
#foreach ($activities as $activity)
{{--implementation--}}
#endforeach
#endsection
in my TabController#showtab1:
public function showtab1(Request $request) {
//Logic here
return view('tab1', ['activities' => $activities]);
}
The optimal scenario is loading the content for each tab only when the tab is clicked by calling a controller function. I have gotten it to work by using routes to change the whole page, but it kind of ruins the advantage of tabs.
You would typically implement this in such a way that you use the same layout, then pass a different parameter through your URL -> controller -> blade include parameter -> blade view.
The example below demonstrates how you can do 'lazy'-load (load only 1 tab at the same time) across files in Laravel:
// /routes/web.php
Route::get('/tabbed-page', 'TabbedPageController#index');
Route::get('/tabbed-page/:tab', 'TabbedPageController#show');
// /App/Http/Controllers/TabbedPageController.php
public function show($request, $tab) {
$data = ['title'=> 'No tab'];
if ($tab === 'tab1') {
$data = ['title' => 'I am tab 1'];
}
return view('page', [
'tab' => $tab,
'data'=> $data
]);
}
public function index($request) {
// open tab1 by default
redirect('/tabbed-page/tab1');
}
{{-- /resources/views/page.php, requested at for example /tabbed-page/tab1 --}}
<nav>
Tab 1
Tab 2
Tab 3
Tab 4
</nav>
<main>
#include($tab, $data)
</main>
{{-- /resources/views/tab1.php, tab2.php, tab3.php, etc.. --}}
<div id="tab1">
<h1>{{ $data['title] }}</h1>
Content ....
</div>

How to retrieve value/name of <a href..> to PHP variable when modal is involved

I have a modal that is common to all the href links, but I need to pass the value of the href so that I can set a PHP session variable to further use info of the href clicked.
For example:
If I click href Tokyo, I need to set a session variable 'prefecture' to 'Tokyo', if I click 'Kanagawa', 'prefecture' = 'Kanagawa'
I cannot use GET as I am calling a modal that is common to all the href links, or may be I am unaware of an efficient method.
Here is the code,
HREF LINKS
<section id="area">
<div class="container inner">
<div class="train-line">
<div class="row">
<h2> Kanto Area </h2>
Tokyo
Kanagawa
Chiba
Saitama
Ibaraki
</div>
</div>
</div>
</section>
MODAL
<div class="modal fade" id="modal-work03" tabindex="-1" role="dialog" aria-labelledby="modal-work03" aria-hidden="true">
.
.
.
Please advice on how to set a PHP session variable when a particular href link is clicked, so that I can use that info on other PHP pages.TIA
Add the onlclick event to your anchors:
Tokyo
Add a javascript function (use jQuery or plain javascript) to the same page or in your included js file:
jQuery function:
function setSessionVariable(varname) {
$.ajax({url: "setsession.php?vname="+varname, success: function(result){
alert("ajax function success: " + result);
}});
Javascript only function:
function setSessionVariable(varname) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML = this.responseText;
}
};
xhttp.open("GET", "setsession.php?vname="+varname, true);
xhttp.send();
}
Add a php file called 'setsession.php'.
In the file you get the request var and set the session variable:
<?php
session_start();
$_SESSION['prefecture'] = $_REQUEST['vname'];
echo("success");
exit(0);
?>
Of course you will want to do some validation and other stuff but that is up to you.
UPDATE
Changed &vname to ?vname
The best option I see is to use ajax and do an onclick of class btn or give them all a classname that is different from btn, mayble modalbtn. Then pass the name as it's data parameters and set the session there. I don't really see a way to do this with only php.
use this code
<section id="area">
<div class="container inner">
<div class="train-line">
<div class="row">
<h2> Kanto Area </h2>
Tokyo
Kanagawa
Chiba
Saitama
Ibaraki
</div>
</div>
</div>
</section>
<script>
$('.btn-large').click(function(){
sessionStorage.city = "";
var city = $(this) .attr('name');
sessionStorage.city = city;
});
</script>
and now this data is stored inside a session variable and whichever page you want to access this variable you can do
sessionStorage.city
hope this helps

Unable to trigger popup box on click event

I'm wrapping up results of ajax request on div and appending to main div in a page. SO if the array of results returned empty, I would like to alert user, saying that no result found and also provide a link for them to click on. When they click a pop up box carrying products by category would popup. Important thing to notice here is,the products are derived via php and ajax scripts.
So When I use onclick event or directly, nothing happens!!!. But if I call empty or HTML pop up it would work. Also the same php scripts contained pop up would work if I trigger it on page load or in the ajax success function. SO I dont understand why only with on click it doesn't work?
This is the pop up I want to trigger on 'click' event
<section id="browse-search-popup" class="mfp-hide white-popup">
<h1>Browse Courses</h1>
Can't find what you're looking for? Tell us here!
<h2>First, pick a learning Zone:</h2>
<div class="row">
<div class="small-12 medium-8 large-8 medium-centered large-centered columns">
<ul class="small-block-grid-2 medium-block-grid-2 large-block-grid-2">
<?php
$tutor = new register();
$data = $tutor->get_maincat();
$i=0;
foreach($data as $k=>$v)
{
$i++;
?>
<li><div class="mainCat_<?php echo $i;?>" id="<?php echo $v['main_cat_id'];?>"><?php echo $v['main_cat_name'];?></div></li>
<?php
}
?>
</ul>
</div>
</div>
<h2>Then, pick a field:</h2>
<div class="row">
<div class="small-12 medium-12 large-12 columns" id="cat">
</div>
</div>
<h2>Finally, choose your Course:</h2>
<div class="row">
<div class="small-12 medium-12 large-12 columns" class="choosen_subjects">
</div>
</div>
<div class="row">
<div class="small-12 medium-12 large-12 columns" id="sub">
</div>
</div>
<input type="submit" id="done" value="Done">
</section>
Ajax request
$("#search_tutor").submit(function() {
var data = {
"action": "test"
};
var subject = $("#subject").val();
data = $(this).serialize() + "&" + $.param(data);
$.ajax({
type: "POST",
dataType: "json",
url: "/fetch_tutor.php", //Relative or absolute path to response.php file
data: data,
success: function(data) {
$("#contents img.loading").remove();
var sizy = data.length;
if(sizy ==0) {
console.log("sorry, cannot locate");
$(".simply-popup-link").trigger("click");
$("#simply-popup").empty();
//This is where I want to trigger the on click
$("#simply-popup").append("Unable to locate the subject you entered, please <a href='#' onclick='browse("+sizy+")' class='yellow'>Browse</a>");
}
console.log("size= "+data.length);
var j=0;
for (i = 0; i < data.length; i++) {
........................
......................
The browse function:
function browse(param) {
//this would work
/* $(".simply-popup-link").trigger("click");
$("#simply-popup").empty();
$("#simply-popup").append("test only"); */
// but not this
$(".browse-search-popup-link").trigger("click");
}
I tried loading the page into the an empty popup box ($("#simply-popup")) like this but doesn't work either:
$("#simply-popup").load('search/browse.php');
Change
$("#simply-popup").append("Unable to locate the subject you entered, please <a href='#' onclick='browse("+sizy+")' class='yellow'>Browse</a>");
to
$("#simply-popup").append("Unable to locate the subject you entered, please <a href='#' class='yellow browse'>Browse</a>");
write a separate code for this
$('body').on('click', '.browse', function() {
$('.browse-search-popup-link').click();
});
Can't you just call that function after append:
$("#simply-popup").append("Unable to locate the subject.....");
browse(sizy);// call it here.
or when you append it in the element then you can call the click:
$("#simply-popup").append("Unable to locate the subject.....");
$("#simply-popup a").click();
$(document.body).append('browse value is 1');
$(document.body).find('a').click();
function browse(num){ $(document.body).find('p').html("<pre>"+num+"</pre>");}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
log out here:
<p></p>

How can I avoid an undesired URL address change after a form submission?

I am working on a bootsrap3 template, which is Ajax based.
My index file has a leftside menu and a conent block middle of the page, every time I click on a subelement of this left menu, an Ajax laod will put the page content in this block(ajax-content).*
Any time I call any page, my URL normally looks something like this /index.php#page-one.php, except when the page contains form submission.
The Problem happens when I add an action attribute (acion="page-one.php") to my form tag.
After the form submission my URL turns to /page-one.php ;
consequently I get a white page containing the page-one.php elements whitout any CSS styling and of course no index-file's elements.
What is the correct and best way to come a cross this issue?
index.php:
<body>
<!--Start Container-->
<div id="main" class="container-fluid">
<div class="row">
<div id="sidebar-left" class="col-xs-2 col-sm-2">
<ul class="nav main-menu">
<li class="dropdown">
<a id="configuration" href="#" class="dropdown-toggle">
<i class="fa fa-gears"></i>
<span class="hidden-xs">Menu-element</span>
</a>
<ul class="dropdown-menu">
<li><a class="ajax-link" href="page-one.php">Menu-Subelement-one</a></li>
<li><a class="ajax-link" href="page-wo.php">Menu-Subelement-two</a></li>
</ul>
</li>
</ul> <!-- end of main-menu-->
</div>
<!--Start Content-->
<div id="content" class="col-xs-12 col-sm-10">
<div class="preloader">
<img src="img.gif" class="loader" alt="preloader"/>
</div>
<!--inside this div a short description/introduction(simple text inside a <p> tag) about the Menu-element will be shown-->
<div id="content-header"></div>
<!--inside this div the page content of the Menu-subelement will be shown-->
<div id="ajax-content"></div>
</div>
<!--End Content-->
</div>
</div>
<!--End Container-->
<script src="plugins/jquery/jquery-2.1.0.min.js"></script>
<script src="plugins/jquery-ui/jquery-ui.min.js"></script>
<script src="plugin/jquery.form.js"></script>
<script src="js/script.js"></script>
And here is my script.js:
//
// Function for load content from url and put in $('.ajax-content') block
//
function LoadAjaxContent(url){
$('.preloader').show();
$.ajax({
mimeType: 'text/html; charset=utf-8', // ! Need set mimeType only when run from local file
url: url,
type: 'GET',
success: function(data) {
$('#ajax-content').html(data);
$('.preloader').hide();
},
error: function (jqXHR, textStatus, errorThrown) {
alert(errorThrown);
},
dataType: "html",
async: false
});
}
//////////////////////////////////////////////////////
document.ready
//////////////////////////////////////////////////////
$(document).ready(function () {
var ajax_url = location.hash.replace(/^#/, '');
if (ajax_url.length < 1) {
ajax_url = 'home.php';
}
LoadAjaxContent(ajax_url);
$('.main-menu').on('click', 'a', function (e) {
var parents = $(this).parents('li');
var li = $(this).closest('li.dropdown');
var another_items = $('.main-menu li').not(parents);
another_items.find('a').removeClass('active');
another_items.find('a').removeClass('active-parent');
if ($(this).hasClass('dropdown-toggle') || $(this).closest('li').find('ul').length == 0) {
$(this).addClass('active-parent');
var current = $(this).next();
if (current.is(':visible')) {
li.find("ul.dropdown-menu").slideUp('fast');
li.find("ul.dropdown-menu a").removeClass('active')
}
else {
another_items.find("ul.dropdown-menu").slideUp('fast');
current.slideDown('fast');
}
}
else {
if (li.find('a.dropdown-toggle').hasClass('active-parent')) {
var pre = $(this).closest('ul.dropdown-menu');
pre.find("li.dropdown").not($(this).closest('li')).find('ul.dropdown-menu').slideUp('fast');
}
}
if ($(this).hasClass('active') == false) {
$(this).parents("ul.dropdown-menu").find('a').removeClass('active');
$(this).addClass('active')
}
if ($(this).hasClass('ajax-link')) {
e.preventDefault();
if ($(this).hasClass('add-full')) {
$('#content').addClass('full-content');
}
else {
$('#content').removeClass('full-content');
}
var url = $(this).attr('href');
window.location.hash = url;
LoadAjaxContent(url);
}
if ($(this).attr('href') == '#') {
e.preventDefault();
}
});
$('#formSubmit').ajaxForm();
});
page-one.php:
<!--some php code here-->
<form class="validateForm" id="formSubmit" action="page-one.php" method="get">
<div class="form-group">
<label>Username</label>
<input type="text" class="form-control" name="username" />
</div>
<div class="form-group">
<div class="col-sm-offset-5 col-sm-8">
<button type="submit" class="btn btn-primary btn-label-left">
<span><i class="fa fa-save"></i> Save</span>
</button>
</div>
</div>
</form>
Thanks!
I had the same issue to solve for the intranet I work on.
For me, the good way to do this is to avoid using submit method and use instead an input button with a js function to send the form data.
In my case, I did this:
<!-- At the top of my webpage -->
<script language='Javascript'>
function loadingAjax(div_id,user,date1,date2)
{
$("#"+div_id).html('<br><center><img src="images/loading.gif"><br><br><font color="#006699" face="arial" size="4"><b>Loading data<br>VPlease wait ...</b></font></center>');
$.ajax({
type: "POST",
url: "activities.php?USER="+user+"&DATE1="+date1+"&DATE2="+date2,
success: function(msg){
$("#"+div_id).html(msg);
}
});
}
</script>
<!-- And here is my form -->
<form id='date_form'>
<input type='text' id='user'><input type='text' id='date1'><input type='text' id='date2'>
<input type='button' onclick="loadingAjax('myDiv',document.getElementById('user').value,document.getElementById('date1').value,document.getElementById('date2').value);">
</form>
This allow to send your form in a separate DIV without having to show to everyone your URL.
MORE: you can even use this function to manage your left side menu selection so that your URL would stay '/index.php' all the time.
Hope this help
Regards
Nico
How do you want to submit the form, using ajax?
If you want to use ajax, you should cancel the default action like you do with your links using e.preventDefault();. Post the javascript that handles the form submit if you need help with that.
If you want to post to page-one.php without using ajax, you could add a header() redirect after the php code that processes the form to redirect to the page that you would like to show after the form gets submitted.
As you are loading content by ajax,
You can post content to page-one.php and redirect user to it's previous page. But it will be difficult manage and show error, success, notification message like form validation errors etc.
Another and I think best solution is to use ajax form submission

Categories