I am trying to implement DirtyForms-style validation library using Lift. What I'd like to do is send the event parameter from a click action to some server-side validation logic. I've found many answers to the problem of passing function arguments to Ajax, but none using Lift.
Here is what I have...
The DirtyField class is a class that keeps track of fields that have been 'dirtied'. Its method isDirty(): Boolean evaluates whether the field value has changed since the page was initialized (this works great).
class DirtyForm(fields: Seq[DirtyField[_]])
{
val popupId = "popup"
private def fieldsDirty(): JsCmd = fields.exists(_.isDirty) match {
case true => Run("""function(e) { e.preventDefault(); $('#""" + popupId + """').dialog(); }""") //prevent them from clicking link if they need to save their data
case false => Noop
}
def seq(): NodeSeq = {
Script(Run("""
$(document).ready(function() {
$(document).on('click', 'a[href]', """ + SHtml.ajaxInvoke(() => fieldsDirty()).toJsCmd + """);
});""".stripMargin)) ++ ConfirmationDiv(popupId) /*div with 'popup' as id*/
}
}
Calling code:
def render = {
//...
val myDirtyForm = new DirtyForm(/*some fields to watch here*/)
"* *+" #> myDirtyForm.seq()
}
Generated javascript:
<script>
// <![CDATA[
$(document).ready(function() {
$(document).on('click', 'a[href]', liftAjax.lift_ajaxHandler("F1336229574104X2J5CL=true", null, null, null));
});
// ]]>
</script>
When this ajax call is invoked on a link click with a dirtied field, I get the following error in the console: The server call succeeded, but the returned Javascript contains an error: SyntaxError: Unexpected token (, which I expect to be because I am trying to use function() where it is not applicable.
TL;DR: My problem revolves around two things:
I want to evaluate whether or not the form is dirty via ajax
If it is dirty, I want to call preventDefault()
Disclaimer: this is my first post, so any suggestions on how to improve the question would be appreciated!
Related
I have a function called generate_form which uses jQuery to create a form and insert it into the page. Several other functions call this general one to create their form, and it in turn returns the form.
In order to do validation, i want the caller to be able to provide their own validation function as the specific use case has non-standard constraints (such as having to issue ajax calls to check/verify things). The issue i'm running into, is i'm not sure how to get the custom validation function into the submit event of the form.
Very simplified and truncated code:
function user_test() {
$('#formcontainer').append(generate_form(
{
name:'test',
id:'user_test_form',
fields:
[
{name:'username',type:'text',id:'username'}
],
validation:function() { return $('#username').length > 0; }
})
);
}
function generate_form(data) {
var form=$('<form>',{id:data['id']});
//SNIP: add fields to form
$(form).submit(function(event) {
event.preventDefault();
//does not work, because data is undefined in this scope
if ( !data['validation']() ) {
//SNIP: validation failed notice
return false;
}
//SNIP: post form
});
return form;
}
Several ways around this. One would be to bind the submission callback to the context of data, so:
$(form).on('submit', function(event) {
event.preventDefault();
if (this.validation && !this.validation()) return false;
}.bind(data));
Another would be to pass data as event data. This is done via the third param of .on():
$(form).on('submit', null, data, function(event) {//...
The original data is then accessible in the callback via event.data.
Also bear in mind you were assuming a validation callback was passed before calling it which, if there isn't one, will error.
The goal:
I want on a Symfony FORM to have two submit buttons. 1st one would be used to validate the form, the 2nd submit button would be used to get away from the form.
By default the fields of the form use the required check before submitting, which means that prior to use the 2nd Submit, the required attributes need to be turned off on DOM <input>. I do that by using some JQuery, event.preventDefault(), I turn off the required on each <input> and then do an event.target.submit().
Then on my Symfony side I expect to catch the button that had been clicked by using the $form->has([button name])->isClicked() function.
The issue:
I have noticed that depending on the browser, the $form->has([button name])->isClicked() doesn't work if some JavaScript with event.preventDefault() and event.target.submit() had been used.
On chrome (Version 51.0.2704.103 m) I get (isClicked = 1 or true):
On firefox (Version 47.0) or Microsoft EDGE 25.* I get (isClicked = false):
The code:
The full code is at the following github.
Emphasis on the code:
In /src/AppBundle/Form/FormType.php you'll find, the code that manages the JavaScript to hold on the Submit, turnoff the required and resume the Submit:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('field1',EmailType::class, array('label'=>'Form Field 1'))
->add('submit',SubmitType::class,array('label'=>'Submit Form'))
->add('get_away_from_form',SubmitType::class,array(
'label'=>'Get away from form',
'attr'=>array(
'onclick'=>'{
//IF THE USER CLICK THE NOT_SUBMIT BUTTON THE REQUIRED FIELD ARE DISABLED BEFORE THE SUBMIT HAPPENS
// Here is the part where are done (see GITHUB code for details):
////`event.preventDefault()`,
//// turn off the `required` on each `<input>`
//// and then do an `event.target.submit()`.
}'
)
));
}
In /src/AppBundle/Controller/DefaultController.php you'll find, the check on $form->get('get_away_from_form')->isClicked():
if($form->isSubmitted() && $form->has('get_away_from_form')){
if($form->get('get_away_from_form')->isClicked() == 1){
$isClicked = 'It works as expected: $form->get(get_away_from_form)->isClicked() = '.$form->get('get_away_from_form')->isClicked();
} else {
$isClicked = 'It DOESN\'T work as expected: $form->get(get_away_from_form)->isClicked() = '.$form->get('get_away_from_form')->isClicked();
}
}
Anyone has an idea?
Why are you using a submit button to get away from the form, instead of just using a link to another page ? It would avoid the need to bypass form validation
In such case one needs to use event.stopPropagation() instead of event.preventDefault().
And there is no need for the event.target.submit().
Now, my JS function associated to the onclick looks like this:
'onclick'=>'{
//IF THE USER CLICK THE NOT_SUBMIT BUTTON THE REQUIRED FIELD ARE DISABLED BEFORE THE SUBMIT HAPPENS
e= \'form\';
$(e).submit(
function(event){
event.stopPropagation();
}
);
function disableReq(e){
var disableReqDef = $.Deferred();
var disableReqDefProm = disableReqDef.promise();
requiredFields = $(e).find(\'[required="required"]\');
requiredFields.each(function(){
$(this).attr(\'required\',false);
});
disableReqDef.resolve();
return disableReqDefProm;
}
var dr = disableReq(e);
$.when(
e,
dr,
undefined
).done(function(e){
$(e).submit(function(event){});
});
}'
Why not use code like the following:
if ( $form->get('get_away_from_form')->isClicked() ){
return $this->redirectToRoute('detourRoute');
}
if ($form->isSubmitted() && $form->isValid()) {
...
Or is it that you MUST use javascript and/or JQuery in your code. My suggestion is simpler... This is only just a suggestion.
UPDATE
Added this error, just says "Error caught"
<script type="text/javascript">
window.onerror = function() {
alert("Error caught");
};
xxx();
</script>
This is not working, I don't understand why.
My php script inserts data properly if called by itself without an if{method=post} statement
I tried with and without an if method = post argument on the php side to get the ajax below to work but I can't tell if the script is being called at all.
My aim is to submit the data without the user knowing, it's a coordinate / dimension update for a variable design interface.
This is my ajax insert which is supposed to work when a function is invoked after the stop is triggered eg. after an object is done moving which the function is invoked properly as I have set up sequential alerts to pop up after certain lines.
$("#form").submit(function(event){
event.preventDefault();
var $form = $( this ),
url = $form.attr( 'action' );
var posting = $.post( url, {
id: $('#id').val(),
name: $('#name').val(),
wname: $('#wname').val(),
xcor: $('#xcor').val(xcor),
ycor: $('#ycor').val(ycor),
xwid: $('#xwid').val(xwid),
yhei: $('#yhei').val(yhei),
photo: $('#photo').val(),
targeturl: $('#targeturl').val()
});
posting.done(function( data ){
alert('success');
});
});
This is wrong
xcor: $('#xcor').val(xcor),
ycor: $('#ycor').val(ycor),
xwid: $('#xwid').val(xwid),
yhei: $('#yhei').val(yhei),
Those object are holding jQuery objects, not a value.
Looks like you want to set the value and use the new value. This makes me cringe, but it would do the job
xcor: $('#xcor').val(xcor).val(),
ycor: $('#ycor').val(ycor).val(),
xwid: $('#xwid').val(xwid).val(),
yhei: $('#yhei').val(yhei).val(),
You would be better off updating them before the call and just using the variable when setting the object. Or just use jQuery serialize() and don't deal with grabbing the elements.
I'm working on my first HTML form that performs an AJAX HTTP POST using jQuery. When a user makes a change to an input text field and tabs out of the field it triggers the AJAX script which in turn calls a PHP script which performs a database update.
I've got this working successfully for my first input field - I would now like to extend this to a 2nd, 3rd etc input fields but want to try and avoid having multiple scripts that perform very similar functions. I'm new to jQuery and AJAX so learning the syntax as I go.
Here's my input fields:
Manager
Phone
Here's my Javascript that is working on the storeManager input field:
<script type="text/javascript">
$(document).ready(function() {
$("#storeManager").change(function(){
var storeManager = $("#storeManager").val();
$.post('editProject.php', { storeManager: storeManager, id: '1E1DDA14-D2C6-4FC8-BA5F-DBCCC7ABAF7F' }, function(data) {
$("#managerRow").addClass("success");
}).fail(function () {
// no data available in this context
$("#managerRow").addClass("danger");
$("#ajaxAlert").addClass("alert alert-danger");
});
});
});
</script>
I essentially need to branch and pass an additional POST parameter to the editProject.php script so it knows which database field to update, and then conditionally add a class to the appropriate row.
Everything I've tried breaks the script when I try and get it to branch or pass a parameter based on the input field that is being edited. I haven't been able to find any examples that show the correct syntax to have the one script that is called by different input fields - I'm presuming this is possible instead of having multiple versions of the same script acting on different fields.
This works for multiple fields. Just call the same function from different input fields. I just broke your code into two parts.
1. onChange function of each individual field, and
2. function call by passing the field parameters.
<script type="text/javascript">
$(document).ready(function() {
$("#storeManager").change(function(){ yourFunction(this) }):
$("#worker").change(function(){ yourFunction(this) }):
$("#someX").change(function(){ yourFunction(this) }):
yourFunction(field)
{
var value = $(field).val();
var inputId=field.id;
$.post('editProject.php', { inputValue: value, id: inputId }, function(data) {
$('#'+inputId+'Row').addClass("success"); // (this looks like: *#storeManagerRow* ) you can change your Row id's accordingly to make your work easier. Eg: for **#storeManager** make this id as **storeManagerRow**
}).fail(function () {
// no data available in this context
$('#'+inputId+'Row').addClass("danger");
$("#ajaxAlert").addClass("alert alert-danger");
});
});
</script>
You just try to post a value. for example type. Which should contain some value for identify the ajax call.
If it is for login, then add type = 'login'. Then check the value of $_POST['type'] and write php according to it
sample.php
if(isset($_POST['type']))
{
if($_POST['type'] == 'login')
{
//your code goes here
}
}
you can use this kind of code :
$("#storeManager, #Manager, #Phone").change(function(){
You could do something like this using :input or a class that they all have
$(":input").on("change", function(){
var text = $(this).val();
var idOfInput = $(this).attr("id");
//your post to php function using the above variables
});
From this you could post the id of the input to your php script using the idOfInput variable which you could then on the php side use a case switch to do a different query depending on which id is sent to the php
Here is a jsfiddle showing how it works
I'm sure there is probably a very simple explanation for this, but I have tried several methods to no avail.
A little new to MVC but I've set up a controller with a conditional search param and now just need a way of passing it the parameter via querystring.
Direcly navigating to:
Collectors/Index?searchName=Tom
works perfectly, so I've set up a Textbox on the view to accept the parameter and am trying to redirect user to searchName= Input.
The problem is that for some reason the window.location.href function is not redirecting the page at all. I've tried window.open method with target set to _self, and that didn't work - however using target _new or not specifying always works.
Is there any reason why the function wouldn't work on the same window?
The following produces an alert before, no redirect and no alert after:
$("#search").click(function () {
alert("before");
window.location.href("../Collector/Index?collectorName=Tom");
alert("after");
however this produces both alerts and the redirect (as well as search results)
$("#search").click(function () {
alert("before");
window.open("../Collector/Index?collectorName=Tom");
alert("after");
});
My controller action:
public ActionResult Index(string collectorName)
{
var db = new CollectorsCRUDController();
var query = db.GetEXCEL_Collectors();
if (!String.IsNullOrEmpty(collectorName))
{
query = query.Where(c => c.CollectorName.Contains(collectorName));
}
return View(query);
}
Any tips would be awesome! Thank you!
Resolved
For anyone else that's having a problem with this:
my problem was that I was using the wrong syntax to call the window.location method...
window.location = URL
not
window.location(URL);
the full code that worked for me
$("#search").click(function () {
var query = $("#searchName").val();
window.location = "/Collector/Index?collectorName=" + query;
});
Edited:
window.location / window.location.href and other variants require setting with the = operator, rather than with parentheses (()) such as used with window.open().
Change: window.location.href("../Collector/Index?collectorName=Tom");
To: window.location.href="../Collector/Index?collectorName=Tom";