issues with jquery-select2 and rails form validation error - javascript

I'm using the select2 jQuery plugin, on a rails form to do autocompleting on a multi-select field. Everything works fine if there are no validation errors on the page. If there is a validation error (not related to this element), then the javascript portion gets an empty element and fails on the JSON.parse call.
However inspecting with chrome-tools show that the Form Data has the correct information under services
services:[{"id":93,"text":"Old School"},{"id":94,"text":"Gels"}],93,94
Here is the view snippet
<%= f.label :services, "Services" %>
<input name="services" type='hidden' id='services' data-values='<%= #services %>' value='<%= #selected_services %>' style="width: 100%"/>
The Javascript looks like this.
var initSel = function (element, callback) {
console.log("intiSel data BRFORE json parse", $(element).val());
try {
var data = JSON.parse($(element).val());
callback(data);
console.log("intiSel data AFTER json parse", data);
} catch (e) {
console.error("Parsing error:", e);
}
}
$(function() {
$("#services").select2({
initSelection: initSel,
createSearchChoice: function(term, data) {
if ( $(data).filter(function() {
return this.text.localeCompare(term)===0;
}).length===0) {return {id:term, text:term};}
},
multiple: true,
data: function (){
var data = $('#services').data('values');
return {results:data};
}
});
});

I had same problem, after validation error the select2 inputs fields were not able to load data.
I'm not sure that it will helps for your case but it can help other stack users with select2 error after validation.
In my case the error was coming from the controller. I was using a before_action filter to get the variables to prepare the options or the data for the select2 inputs fields.
I realize that I was missing some actions in my filter, so the variables were not generated anymore.
class MyController < ApplicationController
before_action :prepare_data, only: [:edit, :update, :new, :create] #now I had all my actions not only edit and new for instance.
private
def prepare_data
#my_var_for_data_select2 = User.all.collect.collect{|u| u.username}
end
end

Related

AJAX form redirecting to empty page instead of logging data

I'm trying to return a JSON string to my javascript to display it, but instead it redirects the page to a page with the JSON values in it. I'm using this in a partial view.
HTML (partial view)
#model ProjectName.Model.EmployeeSearchModel
#using (Ajax.BeginForm("EmployeeSearch", "Base", new AjaxOptions { OnSuccess = "fnAjaxSuccess", OnFailure = "fnAjaxFailure" }))
{
<div>
#Html.EditorFor(x=>x.Social, new { #class="form-control" })<br />
<input type="submit" id="_empSearchSubmitBtn" value="Submit"/>
</div>
}
JS
function fnAjaxSuccess(data) {
console.log(data)
}
function fnAjaxFailure(error) {
alert("An error occured: " + error);
console.log(error);
}
Controller Method (this is in a different controller from the view I'm using it in)
[HttpPost]
public JsonResult EmployeeSearch(EmployeeSearchModel model)
{
return Json("true", JsonRequestBehavior.AllowGet);
}
When I click on the submit button it redirects me to a page with:
"true"
I expect it to be just console.log() on the view I'm in.
to use ajax beginform you need jquery and jquery-unobtrusive-ajax library. You can install it using nuget, search for "jQuery unobtrusive ajax" and then install it. After installing the library add jquery and jquery-unobtrusive-ajax to your layout page.
<script src="~/Scripts/jquery.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>

How to invoke my post method when I'm changing dropdown list in ASP.NET MVC

I'm very new to MVC and Javascript so please be patient with me, I'm working on small application and I came to part when I need to select something from dropdown list and based on that selection I need to redirect user to another View, I also need to determine somehow where I should redirect user, so that is reason why I tried to pass parameter also ( database ID to my post method) but unfortunatelly this is not working, in section below I will post my code:
Method which is sending data to my DropDownList :
public ActionResult ShowArticleGroup()
{
List<ArticleGroup> articlesGroups = GroupsController.GetAllGroups();
ViewBag.articlesGroups = articlesGroups;
return View(articlesGroups);
}
[HttpPost]
public ActionResult ShowArticleGroup(string id)
{
//Here I wanted to take ID of selected Group and because there will be allways 3 Groups I can do if else and Redirect by ID
if(id =="00000000-0000-0000-0000-000000000002")
{
return RedirectToAction("Create","Article");
}
return RedirectToAction("Create", "Article");
}
And my VIEW - there is only one control on the view : just one dropdown, and based on selection I should be redirected to another view, and I wanted here to take ID of selected group and by that I wanted to redirect user to appropiate view:
#model IEnumerable<Model.ArticleGroup>
#{
ViewBag.Title = "Add new article";
}
<h3 style="text-align:center">Choose article group</h3>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true)
<div class="form-group" style="text-align:center">
#Html.DropDownList("Group", new SelectList(ViewBag.articlesGroups, "GroupID", "GroupTitle.Name"), null, new { onchange = "document.location.href = '/Articles/ShowArticleGroup/' + this.options[this.selectedIndex].value;" })
</div>
</div>
}
First of all, usage of location.href on DropDownList seems wrong here:
#Html.DropDownList("Group", new SelectList(ViewBag.articlesGroups, "GroupID", "GroupTitle.Name"), null,
new { onchange = "document.location.href = '/Articles/ShowArticleGroup/' + this.options[this.selectedIndex].value;" })
AFAIK, location.href used for redirect to another page using HTTP GET, hence it will try to call first ShowArticleGroup action method without parameter, and the URL parameter simply ignored since given URL parameter only exist in POST.
To submit the form with DropDownList, you need to handle change event triggering POST into controller action method:
jQuery
<script type="text/javascript">
$(document).ready(function() {
$("#Group").change(function() {
var groupId = $("#Group").val();
$.post('#Url.Action("ShowArticleGroup", "ControllerName")', { id: groupId }, function (response, status) {
// response handling (optional)
});
});
});
</script>
DropDownList
#Html.DropDownList("Group", new SelectList(ViewBag.articlesGroups, "GroupID", "GroupTitle.Name"), null)
I recommend you using strongly-typed DropDownListFor with binding to a viewmodel approach if you want to pass viewmodel contents during form submit.
NB: $.post is shorthand version of $.ajax which uses POST submit method as default.
Related issues:
Autopost back in mvc drop down list
MVC 4 postback on Dropdownlist change

Rails datatables select filter

I have an ajax datatable for my SKUs. For this I am using the ajax-datatables-rails gem. Searcing and sorting works perfectly, but now I'm trying to add a filtering function to my table and it doesn't seem to do anything. I used this example for the filter function: https://datatables.net/examples/api/multi_filter_select.html.
In the example, select boxes are drawn in the footer, but for me the footer is empty. Like the code doesn't run at all. I also don't get any errors.
I initialize my datatable in my coffeescrip file (assets/javascripts/vendor_skus.js.coffee) so I had to translate it to coffeescript. I'm not experienced with coffeescript or using ajax with rails so I'm kind of lost as to what is going wrong.
How I solved my problem:
The standard select boxes were problematic for my situation, as I am using AJAX for my table and the select boxes seemed to only work properly on client side tables. Instead of going with the standard select boxes, I decided to make my own custom filters. These are regular select boxes like so:
<%= select_tag "store-id", options_from_collection_for_select(#stores, "id", "name"), include_blank: true, class:"store-id form-control" %>
<%= select_tag "status", options_for_select([ "Open", "On Hold", "Cancelled", "Closed", "Error" ]), include_blank: true, class:"form-control", multiple:true %>
This is my coffeescript to make jQuery submit the parameters to the server and reload the table onchange:
$ ->
$('#orders-table').DataTable
processing: true
serverSide: true
retrieve: true
pageLength: 50
title: 'orders'
lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]]
ajax: data: (d) ->
d.store_id = $('#store-id').val();
d.status = $('#status').val();
return
$ ->
$('#store-id').on 'change', ->
$('#orders-table').DataTable().ajax.reload()
return
$ ->
$('#status').on 'change', ->
$('#orders-table').DataTable().ajax.reload()
return
In your controller, make sure to pass the parameters along to Datatables like so:
respond_to do |format|
format.html
format.json { render json: OrderDatatable.new(view_context, { store_id: params[:store_id], status: params[:status] }) }
end
And then in your Datatable file, use the parameters to filter your results. In this case I am using a multi select for status, so when the blank value is selected, params[:status].present? results in true. That's why I added a check to see if the first item is an empty string.
def get_raw_records
# insert query here
query = Order.all
query = query.status(params[:status]) if params[:status].present? && (params[:status].count == 1 && params[:status][0] == "") == false
query = query.store(params[:store_id]) if params[:store_id].present?
query.joins(:store)
end
I ran into the same issue when implementing this. I found out that the issue was with this line:
column.search((if val then '^' + val + '$' else ''), true, false).draw()
where coffee script did not like the following bit:
, true, false
After removing it like so:
column.search(if val then '^' + val + '$' else '').draw()
everything worked fine. The caveat to this is, I am not a javascript/coffeescript guy, so what negative impact the result does is beyond me. But like you I am currently battling to get all results to appear in the selectable drop down filter. It only shows any unique values from the current page of data - which is not helpful.
FYI, to get pagination working on this, go to your datatable.rb file and uncomment the correct line toward the top that refers to the pagination you're using. I am using "will_paginate" for bootstrap, so mine looked like this:
include AjaxDatatablesRails::Extensions::WillPaginate
Hope that helps. By chance, did you find a way to show all results in the select filter?
My working code for an ajax datatable filter using the ajax-datatables-rails gem.
in the datatable view I created a table above the datatable to input the range variables, then add some javascript to reload the datatable on change:
<table>
<tbody><tr>
<td>Minimum CWD:</td>
<td><input type="text" id="minCWD" name="minCWD"></td>
</tr>
<tr>
<td>Maximum CWD:</td>
<td><input type="text" id="maxCWD" name="maxCWD"></td>
</tr>
</tbody></table>
<script>
$(document).ready(function () {
// other options
var table = $('#example').DataTable()
$("#minCWD").change(function () {
table.ajax.reload();
});
$("#maxCWD").change(function() {
table.ajax.reload();
});
});
</script>
then to add the filter variables to the ajax call (in the coffee file):
ajax: {
url: $('#example').data('source'),
beforeSend: (xhr) => xhr.setRequestHeader('Content-Type', 'application/json'),
data: (d) ->
$.extend {}, d, 'minCWD': $('#minCWD').val(),
$.extend {}, d, 'maxCWD': $('#maxCWD').val()
}
// note: the beforeSend may not be required
then add a filter in the model_datatable.rb:
def get_raw_records
#YOUR TYPICAL SELECTION...note: I'm using AREL and joining schools with pstats
#now filter by your max min variables
if params['minCWD'].present?
schools = schools.where(pstats[:cwd_percent].gteq(params['minCWD']))
end
if params['maxCWD'].present?
schools = schools.where(pstats[:cwd_percent].lteq(params['maxCWD']))
end
return schools
end
My controller looks like this:
respond_to do |format|
format.html
format.json { render json: ExampleDatatable.new(params, view_context: view_context) }
end
working example here: https://schoolsparrow.com/arizona/schools

Form with JQuery Steps using aui:form tag in Liferay submits no data

I built a portlet and added a entity named Idea. There are two JSPs, one is the view and one the edit.
In the view there is only a button to create a new Idea and a table showing all ideas. Clicking on the button shows the edit jsp.
There is a form with two fieldsets and input stuff.
The "problem" is i cannot use the <aui:form ... stuff because it won't work with JQuery steps (or better, i cannot get it working). So i am using normal tag and also JQuery steps is providing the submit button which is only a <a href="#finish" ...>. So that wont bring the form to submit and the data being in the database.
So I tried to do it within the javascript code of the definition of jquery steps like here:
$(document).ready(function(){
var form = $("#wizard").show();
form.steps(
{
headerTag : "h3",
bodyTag : "fieldset",
transitionEffect : "slideLeft",
onFinishing: function (event, currentIndex) {
alert("Submitted!");
var data = jQuery("#wizard").serialize();
alert(data);
jQuery("#wizard").submit();
form.submit();[/b]
},
onFinished: function (event, currentIndex) {
//I tried also here..
},
});
});
But even if i declare the data explicitely it wont put it in the db.
So my idea was that the "controller" class which calls the "addIdea" function is never called.
How am I solving the problem?
Here is also my jsp code for the form part:
<aui:form id="wizard" class="wizard" action="<%= editIdeaURL %>" method="POST" name="fm">
<h3>Idea</h3>
<aui:fieldset>
<aui:input name="redirect" type="hidden" value="<%= redirect %>" />
<aui:input name="ideaId" type="hidden" value='<%= idea == null ? "" : idea.getIdeaId() %>'/>
<aui:input name="ideaName" />
</aui:fieldset>
<h3>Idea desc</h3>
<aui:fieldset>
<aui:input name="ideaDescription" />
</aui:fieldset>
<aui:button-row>
<aui:button type="submit" />
<aui:button onClick="<%= viewIdeaURL %>" type="cancel" />
</aui:button-row>
</aui:form>
Is there a way to "teach" JQuery Steps the <aui:*** tags? I tried it already while initializing the form but it won't work. To get it working using the aui tags would be great. Because otherwise the Liferay portal wont get the data or it would get it only with hacks right?
€dit: What I forgot, when I submit the form using javascript submit, it creates a new dataentry in the db but no actual data in it.
€dit2:
The editIdeaURL is referenced a bit over the form here:
<portlet:actionURL name='<%=idea == null ? "addIdea" : "updateIdea"%>'
var="editIdeaURL" windowState="normal" />
and the addIdea code looks as follows:
In the IdeaCreation class first this:
public void addIdea(ActionRequest request, ActionResponse response)
throws Exception {
_updateIdea(request);
sendRedirect(request, response);
}
Where _updateIdea() is:
private Idea _updateIdea(ActionRequest request)
throws PortalException, SystemException {
long ideaId = (ParamUtil.getLong(request, "ideaId"));
String ideaName = (ParamUtil.getString(request, "ideaName"));
String ideaDescription = (ParamUtil.getString(request, "ideaDescription"));
ServiceContext serviceContext = ServiceContextFactory.getInstance(
Idea.class.getName(), request);
Idea idea = null;
if (ideaId <= 0) {
idea = IdeaLocalServiceUtil.addIdea(
serviceContext.getUserId(),
serviceContext.getScopeGroupId(), ideaName, ideaDescription,
serviceContext);
} else {
idea = IdeaLocalServiceUtil.getIdea(ideaId);
idea = IdeaLocalServiceUtil.updateIdea(
serviceContext.getUserId(), ideaId, ideaName, ideaDescription,
serviceContext);
}
return idea;
}
And to finally put the data using IdeaLocalServiceImpl:
public Idea addIdea(
long userId, long groupId, String ideaName, String ideaDescription,
ServiceContext serviceContext)
throws PortalException, SystemException {
User user = userPersistence.findByPrimaryKey(userId);
Date now = new Date();
long ideaId =
counterLocalService.increment(Idea.class.getName());
Idea idea = ideaPersistence.create(ideaId);
idea.setIdeaName(ideaName);
idea.setIdeaDescription(ideaDescription);
idea.setGroupId(groupId);
idea.setCompanyId(user.getCompanyId());
idea.setUserId(user.getUserId());
idea.setCreateDate(serviceContext.getCreateDate(now));
idea.setModifiedDate(serviceContext.getModifiedDate(now));
super.addIdea(idea);
return idea;
}
Any ideas?

How to send extra data (ViewBag) to the UI when a webform file is calling an MVC action via JavaScript?

I have a popup called QuoteTemplateSelector.aspx which has a button called btnOK.
<dxe:ASPxButton ID="btnOK" runat="server" Text="Confirm and Export Quote">
<ClientSideEvents Click="function(s,e){
e.processOnServer = false;
<!-- more validation code here... -->
this.location = '/Projects/ExportQuote/' +projNumber
}" />
</dxe:ASPxButton>
the server side code is an MVC controller that returns a file.
public ActionResult ExportQuote(string projectNumber)
{
//more code here ...
//ViewBug.WarningMessage = "The following languages are not supported...
return File(data, "application/vnd.ms-excel", quoteFileName);
}
If the operation goes well, an Excel file is downloaded to the user's browser (as a popup). Now I'd like to send extra information when things go wrong or just to display a warning to the user.
I know that if the UI were an MVC view, I could just snick the warning using the ViewBag. However, the client being an ASPx file, I don't know whether it's going to work.
Any suggestion? Thanks for helping.
I would do this as a two-step process like so:
<dxe:ASPxButton ID="btnOK" runat="server" Text="Confirm and Export Quote">
<ClientSideEvents Click="function(s,e){
e.processOnServer = false;
$.getJSON('/Projects/ValidateQuoteExport/' +projNumber, function (result) {
if(result.validated) {
this.location = '/Projects/ExportQuote/' + projNumber
} else {
// display result.errorMessage to user
}
});
}" />
</dxe:ASPxButton>
Then add an ActionResult for your Validation like so:
public JSONResult ValidateQuoteExport(string projectNumber)
{
// Do the validation that you need
return Json(new { validated = trueorfalse, errorMessage = errorMessage });
}
Making sure you put all of your validation code into a common function that you could call before serving the file, just in case someone URL bypassed the Validation.

Categories