Related
I have a condition in which firstly the ajax request is triggered to fetch respective host url. In case the condition returned is true I want to submit the rails form. The form is submitted correctly but I get the error can't verify authenticity token.
$(document).ready(function() {
var url, email;
$("form#new_user").submit(function(e){
e.preventDefault();
email = document.getElementById("user_email").value;
$.ajax("/return_host", {
type: "GET",
data: {
email: email
},
beforeSend: function(xhr) {
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
},
success: function(data) {
if(data['goto'] == true){
host = data["host"];
url = host + "/users/sign_in";
$("form").attr("action", url);
$("form").trigger('submit.rails');
} else {
location.reload();
}
}
});
});
});
How can I send authenticity token when triggering rails form through ajax success?
Please check whether your form has a hidden input field named authenticity_token or not, for forms generated with rails helpers this field is included by default.
If not then this is what is causing error as rails expects a param called authenticity_token when you post a form.
You can add this on the fly in your success callback as shown below:
success: function(data) {
if(data['goto'] == true){
host = data["host"];
url = host + "/users/sign_in";
var form = $("form");
var authenticityToken = document.createElement("input");
authenticityToken.setAttribute("type", "hidden");
authenticityToken.setAttribute("name", "authenticity_token");
authenticityToken.setAttribute("value", $('meta[name="csrf-token"]').attr('content'));
form.append(authenticityToken);
form.attr("action", url);
form.trigger('submit.rails');
} else {
location.reload();
}
}
Hope it helps!
If you're on Rails 5.1+ I'd recommend using form_with helper to handle the ajax request [https://api.rubyonrails.org/v5.2.1/classes/ActionView/Helpers/FormHelper.html#method-i-form_with].
You'll still be able to hook into the success and error callbacks using code as I've shared below.
```
let form = document.getElementById('my_form')
form.addEventListener('ajax:error', (event) => {
let form = event.target
let [errors, status, xhr] = event.detail
// DO SOMETHING
})
form.addEventListener('ajax:success', (event) => {
let form = event.target
// DO SOMETHING
})
form.addEventListener('ajax:before', (event) => {
let form = event.target
// DO SOMETHING
})
```
This way rails will handle the authenticity token/csrf yet you'll still be able to use Ajax - with option data: { remote: true } to ensure no page reload.
Hope this helps.
With Kendo UI, I am using an autocomplete box to try and retrieve data from my server. It is hitting an ASP.NET MVC controller with the following signature.
public ActionResult aspect(string term){
// ...
}
This means that the request needs to have the correct parameter in the url. Now the issue I am running into is that I cannot discover a way to specify this in the dataSource mechanics. I have read the documentation on parameterMap dozens of times and it makes absolutely no sense to me in any way.
This is complicated further by the fact that the page in question actually has 10-15 autocomplete text boxes at any one time, each dynamically created with dynamic identity.
The code I am using so far is as follows;
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource: {
type: "json",
transport: {
read: {
url: "/search/aspect"
}
}
}
});
So is there anything I can do to tell it how to name the parameter it passes?
To make it more clear what I am trying to do, if I were doing this in jQuery, I would use ...
$.ajax({ url: '/search/aspects', data: { term: (insert the data here) } });
But because of the way all of this works, there is no set "selector" to get the autocomplete input, so I cannot retrieve its value from the input form element.
First, enable server-side filtering by setting this option:
dataSource: {
serverFiltering: true,
Then the value is passed as one of the parameters into the transport.parameterMap function.
If you were to log the object passed in to the parameterMap function like this:
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource: {
serverFiltering: true,
type: "json",
transport: {
read: {
url: "/search/aspect"
},
parameterMap: function (data, action) {
console.log(data);
}
}
}
});
then you would get an object that looks like this:
{
"filter":{
"logic":"and",
"filters":[
{
"value":"something",
"operator":"contains",
"field":"Name",
"ignoreCase":true
}
]
}
}
So you can use this to get the value entered into the AutoComplete box by doing:
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource: {
serverFiltering: true,
type: "json",
transport: {
read: {
url: "/search/aspect"
},
parameterMap: function (data, action) {
if(action === "read") {
return {
term: data.filter.filters[0].value
};
} else {
return data;
}
}
}
}
});
I think that there is a misunderstanding about the relation between DataSource and AutoComplete. AutoComplete has the input and uses a DataSource for retrieving the data: the input does not belong to the AutoComplete and as consequence you cannot get the input that is using a DataSource from a method that is from the DataSource (as transport.read.data or transport.parameterMap).
You need to unique identify which element has the input and the value that it contains.
What I do propose is getting the value using document.activeElement.value. Since you are typing it, the element that has the focus should be the element that you are using.
The code would be:
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource: {
type: "json",
transport: {
read: {
url: "/search/aspect",
},
parameterMap : function (data, type) {
if (type === "read") {
return { term : document.activeElement.value }
}
}
}
}
})
Alternatively, you can enable serverFiltering and then Kendo UI links the input field with the filtering condition. The code would be:
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource : {
serverFiltering: true,
type : "json",
transport : {
read : {
url : "/search/aspect"
},
parameterMap: function (data, type) {
if (type === "read") {
return { term : data.filter.filters[0].value }
}
}
}
}
});
I'm a little confused as to what you're wanting to do. If you are just trying to pass the string term to the controller you can specify the data:
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource: {
type: "json",
transport: {
read: {
url: "/search/aspect",
data: { term: "value" }
}
}
}
})
Thanks for the clarification and help OnaBai. Here is the code that I got working after hours of frustration!
$("#contractsSearchField").kendoComboBox({
dataTextField: "name",
dataValueField: "id",
autoBind: false,
placeholder:'select...',
filter: "contains",// a filter must be present for the datasources serverFiltering argument to work properly.
minLength: 3,
dataSource: new kendo.data.DataSource({
serverFiltering: true,//We must turn on serverFiltering and sorting, otherwise, the combobox only works once and will not change it's values.
serverSorting: true,
group: { field: "searchtype" },
transport: {
read: {
url: "contract.cfc?method=getContractForDropdown",
// We are not passing the data here like we do in the autosuggest. The combobox is a different type of an animal.
dataType: "json",
contentType: "application/json; charset=utf-8", // Note: when posting json via the request body to a coldfusion page, we must use this content type or we will get a 'IllegalArgumentException' on the ColdFusion processing page.
type: "GET"
},//read
// Pass the search term that was typed in by the user. This works because when the user types into the input box, it becomes that active element in the form.
parameterMap : function (data, type) {
if (type === "read") {
return { searchTerm : document.activeElement.value }
//return { searchTerm: data.filter.filters[0].value }
}
}//parameterMap
}//transport
})//dataSource
}); //...kendoComboBox...
I want to have a dropdown with a set of values but also allow the user to "select" a new value not listed there.
I see that select2 supports this if you are using it in tags mode, but is there a way to do it without using tags?
The excellent answer provided by #fmpwizard works for Select2 3.5.2 and below, but it will not work in 4.0.0.
Since very early on (but perhaps not as early as this question), Select2 has supported "tagging": where users can add in their own value if you allow them to. This can be enabled through the tags option, and you can play around with an example in the documentation.
$("select").select2({
tags: true
});
By default, this will create an option that has the same text as the search term that they have entered. You can modify the object that is used if you are looking to mark it in a special way, or create the object remotely once it is selected.
$("select").select2({
tags: true,
createTag: function (params) {
return {
id: params.term,
text: params.term,
newOption: true
}
}
});
In addition to serving as an easy to spot flag on the object passed in through the select2:select event, the extra property also allows you to render the option slightly differently in the result. So if you wanted to visually signal the fact that it is a new option by putting "(new)" next to it, you could do something like this.
$("select").select2({
tags: true,
createTag: function (params) {
return {
id: params.term,
text: params.term,
newOption: true
}
},
templateResult: function (data) {
var $result = $("<span></span>");
$result.text(data.text);
if (data.newOption) {
$result.append(" <em>(new)</em>");
}
return $result;
}
});
For version 4+ check this answer below by Kevin Brown
In Select2 3.5.2 and below, you can use something like:
$(selector).select2({
minimumInputLength:1,
"ajax": {
data:function (term, page) {
return { term:term, page:page };
},
dataType:"json",
quietMillis:100,
results: function (data, page) {
return {results: data.results};
},
"url": url
},
id: function(object) {
return object.text;
},
//Allow manually entered text in drop down.
createSearchChoice:function(term, data) {
if ( $(data).filter( function() {
return this.text.localeCompare(term)===0;
}).length===0) {
return {id:term, text:term};
}
},
});
(taken from an answer on the select2 mailing list, but cannot find the link now)
Just for the sake of keep the code alive, I'm posting #rrauenza Fiddle's code from his comment.
HTML
<input type='hidden' id='tags' style='width:300px'/>
jQuery
$("#tags").select2({
createSearchChoice:function(term, data) {
if ($(data).filter(function() {
return this.text.localeCompare(term)===0;
}).length===0)
{return {id:term, text:term};}
},
multiple: false,
data: [{id: 0, text: 'story'},{id: 1, text: 'bug'},{id: 2, text: 'task'}]
});
Since many of these answers don't work in 4.0+, if you are using ajax, you could have the server add the new value as an option. So it would work like this:
User searches for value (which makes ajax request to server)
If value found great, return the option. If not just have the server append that option like this: [{"text":" my NEW option)","id":"0"}]
When the form is submitted just check to see if that option is in the db and if not create it before saving.
There is a better solution I think now
simply set tagging to true on the select options ?
tags: true
from https://select2.org/tagging
Improvent on #fmpwizard answer:
//Allow manually entered text in drop down.
createSearchChoice:function(term, data) {
if ( $(data).filter( function() {
return term.localeCompare(this.text)===0; //even if the this.text is undefined it works
}).length===0) {
return {id:term, text:term};
}
},
//solution to this error: Uncaught TypeError: Cannot read property 'localeCompare' of undefined
Thanks for the help guys, I used the code below within Codeigniter I I am using version: 3.5.2 of select2.
var results = [];
var location_url = <?php echo json_encode(site_url('job/location')); ?>;
$('.location_select').select2({
ajax: {
url: location_url,
dataType: 'json',
quietMillis: 100,
data: function (term) {
return {
term: term
};
},
results: function (data) {
results = [];
$.each(data, function(index, item){
results.push({
id: item.location_id,
text: item.location_name
});
});
return {
results: results
};
}
},
//Allow manually entered text in drop down.
createSearchChoice:function(term, results) {
if ($(results).filter( function() {
return term.localeCompare(this.text)===0;
}).length===0) {
return {id:term, text:term + ' [New]'};
}
},
});
I just stumbled upon this from Kevin Brown.
https://stackoverflow.com/a/30019966/112680
All you have to do for v4.0.6 is use tags: true parameter.
var text = 'New York Mills';
var term = 'new york mills';
return text.localeCompare(term)===0;
In most cases we need to compare values with insensitive register. And this code will return false, which will lead to the creation of duplicate records in the database. Moreover String.prototype.localeCompare () is not supported by browser Safary and this code will not work in this browser;
return this.text.localeCompare(term)===0;
will better replace to
return this.text.toLowerCase() === term.toLowerCase();
I'm using jquery-ui autocomplete on a page I'm creating. On the same page I have some ajax events going on. During the other ajax events I'm adding an overlay to my page, so that all the links on the website aren't clickable anymore for the user. I don't want that to happen during the autocomplete.
autocomplete:
$(function() {
$( "#search_input" ).autocomplete({
source: '/search_autocomplete/',});
});
ajax:
$.ajax({
url: "/ajax_login/",
login_user: $("#login_user").val(),
password: $("#login_password").val(),
});
ajaxStart:
$("#loading_gif").ajaxStart(function() {
$("#overlay").show();
$(this).show();
});
To prevent the ajaxstart function from being executed during the ajax events where it's not necessary. I add
global:false,
to the corresponding ajaxfunctions. How can I do something similar during the autocomplete without changing the jquery-ui source?
For this you have to omit the shorthand call with source and change the call like this.
$('#search_input').autocomplete({
source: function (request, response) {
var DTO = { "term": request.term };
//var DTO = { "term": $('#search_input').val() };
$.ajax({
data: DTO,
global: false,
type: 'GET',
url: '/search_autocomplete/',
success: function (jobNumbers) {
//var formattedNumbers = $.map(jobNumbersObject, function (item) {
// return {
// label: item.JobName,
// value: item.JobID
// }
//});
return response(jobNumbers);
}
});
}
//source: '/search_autocomplete/'
});
The advantage of this long-hand method is
You can pass more than one parameter. Also the parameter name should not have to be term.
The short-hand notation expects an array of strings. Here you could return an array of objects also.
If you want $.ajax() to work a certain way most of the time but now all the time, then you probably shouldn't change its default behavior.
I recommend creating a function that wraps an ajax request in a function that enables and disables the overlay at the appropriate times. Call this function where you want the overlay to be used, and use plain $.ajax() for your autocomplete.
I would agree that naveen's answer is the best solution. In my case the vast amount of code that would require changing wasn't cost effective as we're in the process of doing a re-write and we needed a short term solution.
You can override the ajax call in jQuery UI, I copied the source for the _initSource function call that handles the AJAX request. Then simply added the global: false to the $.ajax options. The code here is based on jquery-ui 1.9.2, you may have to find the correct source for your version.
$.ui.autocomplete.prototype._initSource = function () {
var array, url,
that = this;
if ( $.isArray(this.options.source) ) {
array = this.options.source;
this.source = function( request, response ) {
response( $.ui.autocomplete.filter( array, request.term ) );
};
} else if ( typeof this.options.source === "string" ) {
url = this.options.source;
this.source = function( request, response ) {
if ( that.xhr ) {
that.xhr.abort();
}
that.xhr = $.ajax({
url: url,
data: request,
dataType: "json",
global: false,
success: function( data ) {
response( data );
},
error: function() {
response( [] );
}
});
};
} else {
this.source = this.options.source;
}
};
public ActionResult DoSomething(string[] arr, bool someBool, int someInt) { }
trying to call the above method from jQuery:
var test = [];
test.push('dog');
test.push('cat');
$container.load('MyController/DoSomething',
{ 'arr[]': test, 'someBool': true, 'someInt': 1 },
function(response, status, xhr) {
// ...
});
the array paramater is null, other params are fine. What am I doing wrong?
Chrome developer tools shows form data being submitted as
arr%5B%5D%5B%5D:dog
arr%5B%5D%5B%5D:cat
someBool:true
someInt:1
not sure whats going on there but doesn't look right to me
If you are using jquery 1.4 you might need to set the traditional parameter to true in order to be compatible with the default model binder format in ASP.NET MVC:
var test = [];
test.push('dog');
test.push('cat');
$.ajax({
url: 'MyController/DoSomething',
type: 'GET',
traditional: true,
data: { arr: test, someBool: true, someInt: 1 },
success: function(result) {
$container.html(result);
}
});
or if you prefer the .load() method:
var data = { arr: test, someBool: true, someInt: 1 };
$container.load('MyController/DoSomething', $.param(data, true),
function(response, status, xhr) {
// ...
});
Just remove []
{ 'arr': test, 'someBool': true, 'someInt': 1 },
Posted values (checking with Firebug).
arr[] dog
arr[] cat
someBool true
someInt 1
Example on jsFiddle
can you see if this problem is similar to yours:
Passing an nested arrays to asp.net mvc using jQuery's $.ajax
Even i was facing error, in passing array from HTML page to aspx page.
my requirement was to load the aspx page in a DIV tag of the html page. on the page load i need to pass these JS array values to aspx page load.
i used below method.
$('#<divTagID>').load("Targetpage.aspx",{"Arr":JSArrValues});
In aspx page load event i can access this values as:
string results = Response["Arr[]"];
Thanks to JQuery API documentation enter link description here and stackoverflow