ng-submit won't work with turbolinks - ruby-on-rails

I have a Rails app using Angular and ngResource to display the content of my "Order" model. Inside the Angular part of the app, I can add and delete objects and it works fine. Only if I navigate to the page through my website (using turbolinks) the "addOrder()" function won't work. The deleteOrder() function and all the rest works, though. I checked what's going on with several console.logs and test functions and discovered that only ng-submit doesn't seem to trigger the function.
This is what the essential parts of my code look like:
app.js
var app = angular.module('shop', ['ngResource']);
$(document).on('ready page:load', function() {
angular.bootstrap(document.body, ['shop'])
});
app.factory('models', ['$resource', function($resource){
...
}]);
app.controller('OrdersCtrl', ['$scope', 'models', function($scope, models){
...
$scope.addOrder = function(){
// doesn't work
...
};
$scope.deleteOrder = function(order){
// works
...
};
}])
index.html.erb
...
<form ng-submit="addOrder()">
<tr>
<td>
<input type="number" step="0.01" ng-model="newOrder.total" class="form-control">
</td>
<td>
<select ng-model="newOrder.product_id" class="form-control">
<option ng-repeat="product in products" value="{{product.id}}">{{product.name}}</option>
</select>
<?td>
<td>
<input type="submit" value="+" class="btn btn-success">
</td>
</tr>
</form>
...
<tr ng-repeat="order in orders | orderBy:'-id':reverse">
{{order.id}}
<button ng-click="deleteOrder(order)" class="btn btn-danger btn-sm"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button>
</tr>
...
The fact that confuses me the most is, that seemingly only ng-submit doesn't work - but all the rest does.
EDIT: SOLUTION
So I did some more research and finally figured out that the problem had nothing to do with turbolinks, Angular or Rails. The problem was, that I couldn't have a form inside a table. That caused the DOM to generate a form closing tag right after the opening tag with none of the inputs inside.

I would try defining something like page:change as I guess that is the only part where turbolinks is not working.
$(document).on('ready page:load page:change', function() {});
Just my first guess on this

I found the solution myself.
So I did some more research and finally figured out that the problem had nothing to do with turbolinks, Angular or Rails. The problem was, that I couldn't have a form inside a table. That caused the DOM to generate a form closing tag right after the opening tag with none of the inputs inside.
So this code:
<form ng-submit="addOrder()">
<tr>
<td>
<input type="number" step="0.01" ng-model="newOrder.total" class="form-control">
</td>
<td>
<select ng-model="newOrder.product_id" class="form-control">
<option ng-repeat="product in products" value="{{product.id}}">{{product.name}}</option>
</select>
<?td>
<td>
<input type="submit" value="+" class="btn btn-success">
</td>
</tr>
</form>
would look like this in the DOM:
<form ng-submit="addOrder()"></form>
<tr>
<td>
<input type="number" step="0.01" ng-model="newOrder.total" class="form-control">
</td>
<td>
<select ng-model="newOrder.product_id" class="form-control">
<option ng-repeat="product in products" value="{{product.id}}">{{product.name}}</option>
</select>
<?td>
<td>
<input type="submit" value="+" class="btn btn-success">
</td>
</tr>

Related

Customise Spring Security 3.1.1 Login form in Grails 3

I have declared Spring Security in my application.yml as a dependency and when running my app the default login form works as expected. I would like to style the form so my application is seamless.
In views/auth I have auth.gsp which contains the following code:
<form method="POST" action="${resource(file: 'j_spring_security_check')}">
<table>
<tr>
<td>Username:</td><td><g:textField name="j_username"/></td>
</tr>
<tr>
<td>Password:</td><td><input name="j_password" type="password"/></td>
</tr>
<tr>
<td colspan="2"><g:submitButton name="login" value="Login"/></td>
</tr>
</table>
</form>
This form appears as expected however when submitting the form nothing happens. I'm assuming it's because {resource(file: 'j_spring_security_check')} is not the action that it should be going to. I have got this code from here and I believe this is written with Grails 2 in mind. Any idea what the correct action is?
The following is the working customised login form:
<form method="POST" action="${resource(file: '/login/authenticate')}" class="form-signin">
<h2 class="form-signin-heading text-center">Login</h2>
<input type="text" class="form-control" name="username" placeholder="Username"/>
<input type="password" class="form-control" name="password" placeholder="Password"/>
<label class="checkbox text-center">
<input type="checkbox" value="remember-me" id="rememberMe" name="remember-me"> Remember me
</label>
<button class="btn btn-lg btn-default btn-block" type="submit">Login</button>
</form>
Key things to note are:
j_spring_security_check is now /login/authenticate
j_username is now username
j_password is now password
Documentation for Spring security 3 which is used for Grails 3 is here
I'm shocked to find that a blog post from six years ago isn't 100% correct. Perhaps you'll have better luck reading the documentation, in particular the "What’s New in Version 3.0" section.

jquery ui spinner malfunctioning with jquery mobile

I'm trying to use jquery ui spinners in a table with jquery mobile 1.4.0
<div class="table_data">
<table data-role="table" data-mode="reflow" class="ui-responsive table-stroke">
<thead>
<tr>
<th>Address</th>
<th>Doorbells</th>
<th>Mailboxes</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>
<input type="text" class="spinner" name="doorbells"/>
</td>
<td>
<input type="text" class="spinner" name="mailboxes"/>
</td>
</tr>
<tr>
<td>2</td>
<td>
<input type="text" class="spinner" name="doorbells"/>
</td>
<td>
<input type="text" class="spinner" name="mailboxes"/>
</td>
</tr>
<tr>
<td>3</td>
<td>
<input type="text" class="spinner" name="doorbells"/>
</td>
<td>
<input type="text" class="spinner" name="mailboxes"/>
</td>
</tr>
</tbody>
</table>
</div>
<script>
$( ".spinner" ).spinner();
</script>
In the jsfiddle link below you can see my problem. The buttons don't show up in the correct place and they don't even work anymore.
http://jsfiddle.net/murtho/ZZqu6/5/
When I do not include the jquery ui js and css file the spinners work just fine. I need the mobile ui for other features in my application, but I also wish to implement the jquery spinner (of an alternative solution)
This is how it should be working:
http://jsfiddle.net/murtho/tf89L/2/
jQuery UI and jQuery mobile don't play together that well.
For your number spinner, you can fix the formatting with one extra line of code to remove the jQM classes from the spinner button divs:
$(document).on("pagebeforeshow", "#page1", function(){
$( ".spinner" ).spinner();
$(".ui-spinner div" ).removeClass(function() {
return $( this ).attr( "class" );
});
});
Here is your updated FIDDLE
Another option is to set type="number" on the input boxes; however, not all browsers understand this.
You will need to see if jQuery UI causes any other problems with your particular application...

CodeIgnitier CSRF protection how submit form which is loaded via jquery tabs

I'm working on some backend project and want to load form via jQueryUI tabs
<div id="parameters_tabs" style="width:920px;">
<ul>
<li><?=$this->lang->line('tab_name')?></li>
</ul>
</div>
in response I produce few forms as in example below:
<?
for ($i = 0; $i < count($groups); $i++)
{
?>
<form id="group_form<?=$i?>" method="POST" action="<?=base_url()?>update_group">
<input type="hidden" name="<?=$this->config->item('csrf_token_name')?>" value="<?=$token?>" />
<input type="hidden" name="id" value="<?=$groups[$i]['id']?>" />
<tr>
<td>
<input type="text" value="<?=$groups[$i]['name']?>" name="name" />
</td>
<td>
<input type="text" value="<?=$groups[$i]['short_name']?>" name="short_name" />
</td>
<td>
<textarea cols="80" rows="4" name="desc"><?=$mgroups[$i]['desc']?></textarea>
</td>
<td style="width: 30px">
<a class="save" onclick="$('#group_form<?=$i?>').submit();"><?=$this->lang->line('save')?></a>
</td>
</tr>
</form>
<?
}
?>
when clicking on "save" I got standard error about CSRF protection:
"An Error Was Encountered
The action you have requested is not allowed."
Can anyone help me and tell where I made mistake? Of course in source I see proper csrf_token_name.
This article helped me when I was experiencing the same issue. Using the built-in form helper form_open() function might also help solve the problem (as it generates the hidden CSRF field for you).

reading from a file using the input type=file in grails

Hi I have the following code in my grails gsp
<form action="upload-script-url" method="post" enctype="multipart/form-data">
<table class="table"style="width: 75%">
<tr>
<td>
<span style="font-weight: bold; ">Select the Source File:</span>
<input size="75" type="file" id="payload" name="payload"/>
</td>
</tr>
<tr>
<td>
<input type="submit" class="red" id="Run">Run</button>
</td>
</tr>
</table>
</form>
I read the form parameters from: here
Are those right parameters in the html form?
Now how should I proceed to read the data from the selected file? do I have to use the apache commons fileupload api ?
Thanks
request.getFile("payload")
and you will get a CommonsMultipartFile
If you take some time to (again) actually look at the documentation you will see how to do it...

partial view coming without validation attributes (ASP.NET MVC 3)

A weird thing keeps happening on one of my ASP.NET MVC 3 apps.
I am fetching insert rows via jQuery Ajax api and there is no problem with that. But when I get the necessary partial view back, it is coming without validation attributes and I am unable to rebind the validation for those rows.
Here is what I get as ajax response:
<input type="hidden" name="accommPropertyPeriods.index" autocomplete="off" value="ccaa15b3-76f1-4215-8bb5-a62d700bfc1e" />
<table style="width:100%;">
<tr>
<td>
<div class="editor-field">
<select class="chzn-select-deselect" data-placeholder="Choose an Alias..." id="accommPropertyPeriods_ccaa15b3-76f1-4215-8bb5-a62d700bfc1e__AccommPropertySeasonPeriodAliasID" name="accommPropertyPeriods[ccaa15b3-76f1-4215-8bb5-a62d700bfc1e].AccommPropertySeasonPeriodAliasID" style="min-width:100px;"><option value="302">A</option>
<option value="303">B</option>
<option value="304">C</option>
<option value="305">D</option>
</select>
</div>
</td>
<td>
<div class="editor-field">
<input class="datefield" id="accommPropertyPeriods_ccaa15b3-76f1-4215-8bb5-a62d700bfc1e__PeriodStartsAt" name="accommPropertyPeriods[ccaa15b3-76f1-4215-8bb5-a62d700bfc1e].PeriodStartsAt" type="text" value="" />
</div>
</td>
<td>
<div class="editor-field">
<input class="datefield" id="accommPropertyPeriods_ccaa15b3-76f1-4215-8bb5-a62d700bfc1e__PeriodEndsAt" name="accommPropertyPeriods[ccaa15b3-76f1-4215-8bb5-a62d700bfc1e].PeriodEndsAt" type="text" value="" />
</div>
</td>
</tr>
</table>
Here is what I should be getting :
<input type="hidden" name="accommPropertyPeriods.index" autocomplete="off" value="84ddd0f5-a3e2-4f10-8e67-f32528c6393d" />
<table style="width:100%;">
<tr>
<td>
<div class="editor-field">
<select class="chzn-select-deselect" data-placeholder="Choose an Alias..." data-val="true" data-val-number="The field AccommPropertySeasonPeriodAliasID must be a number." data-val-required="The AccommPropertySeasonPeriodAliasID field is required." id="accommPropertyPeriods_84ddd0f5-a3e2-4f10-8e67-f32528c6393d__AccommPropertySeasonPeriodAliasID" name="accommPropertyPeriods[84ddd0f5-a3e2-4f10-8e67-f32528c6393d].AccommPropertySeasonPeriodAliasID" style="min-width:100px;"><option value="302">A</option>
<option value="303">B</option>
<option value="304">C</option>
<option value="305">D</option>
</select>
<span class="field-validation-valid" data-valmsg-for="accommPropertyPeriods[84ddd0f5-a3e2-4f10-8e67-f32528c6393d].AccommPropertySeasonPeriodAliasID" data-valmsg-replace="false">*</span>
</div>
</td>
<td>
<div class="editor-field">
<input class="datefield" data-val="true" data-val-required="The PeriodStartsAt field is required." id="accommPropertyPeriods_84ddd0f5-a3e2-4f10-8e67-f32528c6393d__PeriodStartsAt" name="accommPropertyPeriods[84ddd0f5-a3e2-4f10-8e67-f32528c6393d].PeriodStartsAt" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="accommPropertyPeriods[84ddd0f5-a3e2-4f10-8e67-f32528c6393d].PeriodEndsAt" data-valmsg-replace="false">*</span>
</div>
</td>
<td>
<div class="editor-field">
<input class="datefield" data-val="true" data-val-required="The PeriodEndsAt field is required." id="accommPropertyPeriods_84ddd0f5-a3e2-4f10-8e67-f32528c6393d__PeriodEndsAt" name="accommPropertyPeriods[84ddd0f5-a3e2-4f10-8e67-f32528c6393d].PeriodEndsAt" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="accommPropertyPeriods[84ddd0f5-a3e2-4f10-8e67-f32528c6393d].PeriodEndsAt" data-valmsg-replace="false">*</span>
</div>
</td>
</tr>
</table>
GUIDs don't have to be the same. I am doing so-called non-sequential binding.
Here is the the action which I am invoking through jquery ajax to get a new insert row:
[HttpPost]
public PartialViewResult accommPropertySeasonPeriodCreatePartialView(int id, int subid) {
//some other stuff going on here. non-related to partial view.
return PartialView("_AccommPropertySeasonPeriodCreatePartialView");
}
I am nearly out of my mind to figure out why this is happening. Any idea?
The Html.* helpers such as Html.TextBoxFor, Html.CheckBoxFor, ... emit validation attributes only if used inside a form. So make sure you wrap them in a Html.BeginForm call. As far as client side validation is concerned, you should call the jQuery.validator.unobtrusive.parse method after you update your DOM in order to reapply client validation. And yet another article.
If you don't have a form you can cheat and put the following in the partial:
#model MyViewModel
#{
ViewContext.FormContext = new FormContext();
}
#Html.EditorFor(x => x.Foo)
Now the helper will emit data-* validation attributes on the input field.

Resources