I need help with the form submission and saving to db in my ruby camping web app.
The app itself is a quality assurance app. Users fill in forms for any errors detected during the quality check. The problem is that the check can take for a couple of hours or in extreme cases even more. During that time, in order to save the data, users have to submit the form several times. Currently I've set it up so that the users submit the form and are immediately redirected back to the form.
How would I go about to enable some sort of autosaving, let's say every 10 minutes or upon each change to the form so users don't have to do it manually.
This is quite difficult for me because I'm not a programmer per say, butI learn as go alogn to optimize my processes.
I've been reading about ajax and jquery but I'd really appreciate if someone could point me in the right direction since I don't know where to start and camping examples are rather scarce.
EDIT
Some additional infos:
I've successfully implemented jQuery to my camping app and I can manipulate html elements, but AJAX doesn't work. Firebug console doesn't return any errors.
Here are my assumptions:
If the form can be successfully submitted manually I don't have to change anything in my controller or view in order for AJAX to work, right?
The url passed to AJAX doesn't have to include the object id for which I want to submitt the form, right? I'm passing the '/edit' url and the full url to the relevant object is for example '/edit/5'.
Here is the code from the html head:
script :type => 'text/javascript' do "
$(document).ready(function() {
$('#np').change(function() {
$('#add_form').submit(function() {
$.ajax({
type: 'POST',
url: '/edit',
data: $('#add_form').serialize(),
});
});
});
$('#search_indiv_form').click(function(){
$('#search_indiv_form_toggle').toggle(700);
});
});"
end
Are there any errors in my ajax code to prevent the form being submitted?
thank you.
regards,
seba
Related
I have a search page done using Laravel. On that page there is a button which makes an AJAX call to another url. That page is paginated, so the user can be on the first, second or last page.
My problem is, How can I bring the user back to the same page and point that he was.
Or, Is there a way to just call a method to perform some actions on the database?
Thats my Ajax Call:
$.ajax({
url: $(this).attr('data-href'),
dataType: 'html',
success:function(data) {
$('#ajaxResponse').html(data);
$.growl.notice({ title: 'Voto', message: 'Computado com sucesso' });
$(this).find('.fa').toggleClass('fa-heart-o fa-heart');
}
});
I know if i take the $('#ajaxResponse').html(data); bit it is going to perform the change but not update the numbers that i need. Any ideas?
Here is the documentation for pagination in Laravel with JSON. As you can see, when you paginate your data, the resulting JSON object will contain information about the next and previous pages. Update the links your users click with the provided information and they should see the correct data.
You can try to store the actual page in a session key and use a controller to check this key and display the page that you want. In this case you can keep your ajax call as it is and change only your laravel controller ad view.
Ok, this idea might seem quite a bit crazy and it kindo' is (at least for me at my level).
I have a fairly standarad rails app (some content pages, a blog, a news block, some authentication). And I want to make it into a single page app.
What I want to accomplish is:
All the pages are fetched through AJAX like when using turbolinks, except that the AJAX returns only the view part (the yield part in the layout) withought the layout itself, which stays the same (less data in the responces, quicker render and load time).
The pages are mostly just static html with AngularJS markup so not much to process.
All the actual data is loaded separately through JSON and populated in the view.
Also the url and the page title get changed accordingly.
I've been thinking about this concept for quite a while and I just can't seem to come up with a solution. At this point I've got to some ideas on how this actualy might be done along with some problems I can't pass. Any ideas or solutions are greatly appreciated. Or might be I've just gone crazy and 3 small requests to load a page are worse then I big that needs all the rendering done on server side.
So, here's my idea and known problems.
When user first visits the app, the view template with angular markup is rendered regularly and the second request comes from the Angular Resource.
Then on ngClick on any link that adress is sent to ngInclude of the content wrapper.
How do I bind that onClick on any link and how can I exclude certain links from that bind (e.g. links to external authentication services)?
How do I tell the server not to render the layout if the request is comming from Angular? I though about adding a parameter to the request, but there might be a better idea.
When ngInclude gets the requested template, it fires the ngInit functions of the controllers (usually a single one) in that template and gets the data from the server as JSON (along with the proper page title).
Angular populates the template with the received data, sets the browser url to the url of the link and sets the page title to what it just got.
How do I change the page title and the page url? The title can be changed using jQuery, but is there a way through Angular itself?
Again, I keep thinking about some kind of animation to make this change more fancy.
Profit!
So. What do you guys think?
OK, in case enyone ever finds this idea worth thinking about.
The key can be solved as follows.
Server-side decision of whether to render the view or not.
Use a param in the ngInclude and set the layout: false in the controller if that param is present.
Have not found an easier way.
Client-side binding all links except those that have a particular class no-ajax
Here's a directive that does it.
App.directive('allClicks', function($parse) {
return {
restrict: 'A',
transclude: true,
replace: true,
link: function(scope, element, attrs) {
var $a = element.find('a').not($('a.no-ajax')),
fn = $parse(attrs['allLinks']);
$a.on('click', function(event) {
event.preventDefault();
scope.$apply(function() {
var $this = angular.element(event.target);
fn(scope, {
$event: event,
$href: $this.attr('href'),
$link: $this
});
});
});
}
};
})
And then use it on some wrapper div or body tag like <body ng-controller="WrapperCtrl" all-links="ajaxLink($href)"> and then in your content div do <div id="content" ng-include="current_page_template">
In your angular controller set the current_page template to the document.URL and implement that ajaxLink function.
$scope.ajaxLink = function(path) {
$scope.current_page_template = path+"?nolayout=true";
}
And then when you get your JSON with your data from the server don't forget to use history.pushState to set the url line and document.title = to setr the title.
I'm confused as to how to accomplish this. I have a page which, has a popup filter, which has some input elements and an "Apply" button (not a submit). When the button is clicked, two jquery .get() calls are made, which load a graph, a DataTables grid, photos, and miscellaneous info into four separate tabs. Inside the graph, if one clicks on a particular element, the user is taken to another page where the data is drilled down to a finer level. All this works well.
The problem is if the user decides to go back to the original page, but with the ajax generated graph/grid/photos etc. Originally I thought that I would store a session variable with the filter variables used to form the original query, and on returning to the page, if the session var was found, the original ajax call would be made again, re-populating the tabs.
The problem that I find with this method is that Coldfusion doesn't recognize that the session variable has been set when returning to the page using the browser's back button. If I dump out the session var at both the original and the second page, I can see the newly set var at the second page, and I can see it if I go to the original page through the navigation menu, but NOT if I use the back button.
SO.... from reading posts on here about ajax browser history plugins, it seems that there are various jquery plugins which help with this, including BBQ. The problem that I see with this approach is that it requires the use of anchor elements to trigger it, and then modifies the query string using the anchors' href attributes. I suppose that I could modify the page to include a hidden anchor.
My question, at long last is: is an ajax history plugin like BBQ the best way to accomplish this, or is there a way to make Coldfusion see the newly created session var when returning to the page via the back button? Or, should I consider re-architecting the page so that the ajax calls are replaced by a form submission back to the page instead?
Thanks in advance, as always.
EDIT: some code to help clarify things:
Here's the button that makes the original ajax calls:
<button id="applyFilter">APPLY</button>
and part of the js called on #applyFilter, wrapped in $(document).ready():
$('#applyFilter').click(function(){
// fill in the Photos tab
$.get('tracking/listPhotos.cfm',
{
id: id,
randParam: Math.random()
},
function(response){
$('#tabs-photos').html(response);
}
);
});
Finally, when the user calls the drill-down on the ajax generated graph, it uses the MaintAction form which has been populated with the needed variables:
function DrillDown() {
//get the necessary variables and populate the form inputs
document.MaintAction.action = "index.cfm?file=somepage.cfm&Config=someConfig";
document.MaintAction.submit();
}
and that takes us to the new page, from which we'd like to return to the first page but with the ajax-loaded photos.
The best bet is to use the BBQ method. For this, you don't have to actually include the anchor tags in your page; in fact, doing so would cause problems. This page: http://ajaxpatterns.org/Unique_URLs explains how the underlying process works. I'm sure a jQuery plugin would make the actual implementation much easier.
Regarding your other question, about how this could be done with session variables - I've actually done something similar to that, prior to learning about the BBQ method. This was specifically to save the state of a jqGrid component, but it could be easily changed to support any particular Ajax state. Basically, what I did was keep a session variable around for each instance of each component that stored the last parameters passed to the server via AJAX requests. Then, on the client side, the first thing I did was run a synchronous XHR request back to the server to fetch the state from that session variable. Using the callback method for that synchronous request, I then set up the components on my page using those saved parameters. This worked for me, but if I had to do it again I would definitely go with the BBQ method because it is much simpler to deal with and also allows more than one level of history.
Some example code based on your update:
$('#applyFilter').click(function(){
var id = $("#filterid").val(); // assumes the below id value is stored in some input on the page with the id "filterid"
// fill in the Photos tab
$.get('tracking/listPhotos.cfm',
{
id: id // I'm assuming this is what you need to remember when the page is returned to via a back-button...
//randParam: Math.random() - I assume this is to prevent caching? See below
},
function(response){
$('#tabs-photos').html(response);
}
);
});
/* fixes stupid caching behavior, primarily in IE */
$.ajaxSetup({ cache: false });
$.ajax({
async: false,
url: 'tracking/listPhotosSessionKeeper.cfm',
success: function (data, textStatus, XMLHttpRequest)
{
if (data.length)
{
$("#filterid").val(data);
$('#applyFilter').trigger('click');
}
}
});
This is what you need on the client-side to fetch the state of the photo list. On the server side, you'll need to add this modification to tracking/listPhotos.cfm:
<cfset session.lastUsedPhotoFilterID = URL.id>
And add this new one-line file, tracking/listPhotosSessionKeeper.cfm:
<cfif IsDefined("session.lastUsedPhotoFilterID")><cfoutput>#session.lastUsedPhotoFilterID#</cfoutput></cfif>
Together these changes will keep track of the last ID used by the user, and will load it up each time the page is rendered (whether via a back button, or simply by the user revisiting the page).
hi
sorry for the bad title but I'm not 100% sure what I need for this problem
I created a welcome page and then when you click on links you get more information, for example:
Click Me
And then the php would get the information based on the id.
so the information received is reloaded on the page after the pages refreshes
what I would like to be able to do is when user clicks on the link, use jquery to not allow the link to run but still run the url in the background (without refreshing the page)
I have no idea where to start from so I really hope you could help
thanks
In a nutshell, it's called Ajax: sending an HTTP request to your server through javaScript, and receiving a response which can contain results, data, or other information.
You mention jQuery, here are the docs about that:
http://api.jquery.com/jQuery.get/
http://api.jquery.com/jQuery.post/
are convenience methods, which encapsulate $.ajax with preset options.
http://api.jquery.com/category/ajax/ is an overview of the whole system in jQuery.
The basics go like
//include jquery, etc.
$(document).ready(function(){
$('#some_element').click(function(){
$.get('some_url_on_your_server.php',{'data':'whatever params'},function(data){
do_something();//
},'json');
});
This will bind an element to make an Ajax call on click, and then you use the function ('success' function, in $.ajax) to handle the json data.
Have your server send back the data in JSON by using json_encode in php. Be sure to send the right header back, like
<?php
header('Content-Type: application/json');
echo json_encode($some_array);
exit;
There's a lot of resources on the web and SO for learning about Ajax, it's a big topic. Best of luck.
Make a JavaScript function, like sendData(linkId) and then each tag would have an onclick event called sendData(this). SendData(linkId) can then do an HTTPRequest (also known as an asynchronous or AJAX request) to a php file, let's call it handler.php, which receives GET or POST methods. I prefer using the prototype framework to do this kind of thing (you can get it at prototypejs.org).
Okay, now that I have said all that, let's look into the nitty-gritty of how to do this (way simplified for illustrative purposes).
Download the prototype script, save it on your server (like prototype/prototype.js, for example) and then put somewhere in your html <script type='text/javascript' language='Javascript' src='prototype/prototype.js'></script>
Your tags would look like this:<a id='exampleLink' onclick = 'sendData(this)'>Click me!</a>
You need JavaScript to do this: function sendData(tagId){
var url = 'handler.php?' + 'id=' + tagId;
var request = new AJAX.Request(url, {method = 'get'});
}
Finally, you need a php file (let's call it handler.php) that has the following: <?php
$tag_to_get = $_GET['tagId'];
do_a_php_function($tag_to_get);
?>
That's it in a nutshell, but it's worth mentioning that you should give your user some sort of feedback that clicking link did something. Otherwise he will click the link furiously waiting for something to happen, when it is actually doing just what its supposed to but in secret. You do that by making your php script echo something at the end, like 'Success!', and then add an onSuccess parameter to your JavaScript's new Ajax.Request. I'll let you read how to do that on your own because the prototype website explains how to receive a response from the handler and put the feedback somewhere in your HTML without making the user refresh.
you can achieve that behavior with a jquery function called $.get ... you can get more information on how to use here http://api.jquery.com/jQuery.get/
If you really want to (and I don't think you really do), you can use XMLHTTPRequest (wrapped in jQuery.get) to facilitate loading content into the page without page refreshing. You want an id or class on that tag, i.e. Click Me, and then:
<script>
$(".fetch").bind("click", function(evt)
{
$.get(this.attr("href"), function(data)
{
$("#whereIWantMyContent").html(data);
});
evt.preventDefault();
});
</script>
I would recommend you use AJAX to start with. A good place to being is http://www.w3schools.com/Ajax/Default.Asp
The link comes with a handy AJAX ASP/PHP Example too =))
Good Luck.
Good afternoon everyone. I was wondering if there is anyway to have the MVC framework automatically wire up the data-val* attributes on the controls or do we need to manually create and apply the attributes to dynamic content?
I have a view that initially calls a partial view passing in the main viewmodel. This partial view is bound to a complex property on my main viewmodel. The partial view simply contains a set of cascading dropdown lists. On initial load of the page I have a call to #Html.Partial("PartialName", Model), the two dropdown lists’ validation works perfectly if I try to submit without selecting proper values. I also have another button on the page that if clicked loads another instance of the partial view on the page. If I now try to submit the form these controls, although they are bound to the same model and although I have set the correct .ValidationMessageFor helpers, no validation appears for them since the dropdownlists do not appear to be generated with the data-val* attributes. Is there any way that I can get them to appear correctly? I also noticed that the associated <span /> tag associated to the .ValidationMessageFor is not generated either. Has anyone run into this problem as well, if so how did you resolved?
UPDATE
Here is the javascript function that I call to load the partial on the button's onClick event:
function AddNewVehicle() {
$.ajax({
type: 'GET',
url: '/ReservationWizard/AddVehicleToReservation',
data: $('#reservation-wizard-form').serialize(),
dataType: 'HTML',
async: true,
success: function (data) {
if (data != null) {
$('#vehicle-selection-container').append(data);
}
}
});
}
The problem is that if you are not inside a form context, the HTML helpers such as TextBoxFor do not output any client validation data-* attributes. The first time when the page loads you invoke your Html.RenderPartial inside an Html.BeginForm() but later when you use AJAX to append form elements there is no longer this form context and there won't be any data-* client validation attributes generated. One possible solution would be to put the form inside the partial and then update the entire form during the AJAX call and in the success callback re-parse the client validation rules using $.validator.unobtrusive.parse('#vehicle-selection-container').
But if you want to keep only a single element inside the partial you are pretty much on your own :-) Here's a blog post which covers your scenario that you might take a look at.
So what can I say: unobtrusive client validation is great on paper and Scott Gu's blog posts but at some stage of the development of real world applications people start to realize its limitations. That's one of the reasons why I directly use the jquery.validate plugin and no MS jquery.unobtrusive. And, yes I know that I repeat my server validation logic in the javascript and yes I don't care because I have total control. Oh, and on the server I use FluentValidation.NET instead of data annotations for pretty much the same reasons as the client side part :-)
So maybe some day in MVC 4 Microsoft will finally make validation right (imperative vs declarative) but until this day comes, we just need to be searching for workarounds.