How to titleize/captialize words (with the exception of some prepositions) in the text_area as the user types in their words in real time?
<%= f.text_area :name %>
For example, to create the same behavior as this website: http://titlecapitalization.com/
If you are using Jquery, your problem will be solved by code given below.
function makeTitle(slug) {
var words = slug.split(' ');
$.each(words, function(index, word){
words[index] = word.charAt(0).toUpperCase() + word.slice(1);
});
return words.join(' ');
}
$(element_selector).on('keyup', function(){ $(this).val( makeTitle($(this).val())) })
Related
I want to create a table where rows and buttons can be added via a button (one for rows, one for columns). The columns consist of one collection_select (to select a device) as the title and text_field in each row (for test results for this device in each row).
The columns consist of several text_field and one text_area (for different test specifications).
I use this code to add a column in _form.html.erb:
<%= bootstrap_form_with(model: Testreport.new, local: true) do |f| %>
<table class="table" id="testreport_table">
...
<input type=button id='col_1_button' value="+" onclick="insertColumn();">
...
</table>
function insertColumn() {
let table = document.getElementById('testreport_table'),
columns_count = table.rows[1].cells.length,
rows_count = table.getElementsByTagName('tr').length,
i;
document.getElementById('button_row').colSpan = columns_count + 1;
<% a = f.collection_select( :devicesample_id, Devicesample.order(:name), :id, :name, include_blank: false, label: "Device Sample") %>
table.rows[1].insertCell(columns_count).innerHTML = '<%= a %>'
for (i = 2; i < (rows_count - 1); i++) {
table.rows[i].insertCell(columns_count).innerHTML = "Added Column";
}
return false;
}
However, rendering the page throws this error (Chrome): Uncaught SyntaxError: Invalid or unexpected token
The error is in this generated line:
table.rows[1].append('<select name="testreport[devicesample_id]" id="testreport_devicesample_id"><option value="4">Hisense 6486 LATAM</option>
Whole generated code:
function insertColumn() {
let table = document.getElementById('testreport_table'),
columns_count = table.rows[1].cells.length,
rows_count = table.getElementsByTagName('tr').length,
i;
document.getElementById('button_row').colSpan = columns_count + 1;
table.rows[1].insertCell(columns_count).innerHTML = '<div class="form-group"><label for="testreport_devicesample_id">Device Sample</label><select class="form-control" name="testreport[devicesample_id]" id="testreport_devicesample_id"><option value="4">Device A LATAM</option>
<option value="1">Device B </option>
<option value="3">Device C </option></select></div>';
for (i = 2; i < (rows_count - 1); i++) {
table.rows[i].insertCell(columns_count).innerHTML = "Added Column";
}
return false;
}
When I just copy the same exact collection_select to the regular body, it displays fine. What is causing this error? I have the same issue if I want to add a text_area, while text_field is working fine.
I am suspecting that it has something to do with the multi-line property of these fields, but even if that is the case I do not know how to avoid this.
I am new to Ruby, Rails and Javascript. I use:
ruby 2.6.5p114 (2019-10-01 revision 67812) [x64-mingw32]
Rails 6.0.2.1
Chrome Version 79.0.3945.130
(edit: replaced table.rows[1].append('<%= a %>');with table.rows[1].insertCell(columns_count).innerHTML = '<%= a %>'': which was the original code)
You get Uncaught SyntaxError: Invalid or unexpected token error because you have a multiline string in your code.
So change quotes from
table.rows[1].insertCell(columns_count).innerHTML = '<%= a %>'
to
table.rows[1].insertCell(columns_count).innerHTML = `<%= a %>`
You can also remove new lines:
table.rows[1].insertCell(columns_count).innerHTML = '<%= a.tr("\n","") %>'
Of course, it's better to move HTML generation to javascript side, but it's another topic :)
submitBtn.addEventListener("click",()=>{
//check to see the answer
const answer=getSelected();
if(answer){
if(answer === quizData[currentQuiz].correct){
score++;
}
currentQuiz++;
if(currentQuiz < quizData.length){
loadQuiz();
}
else{
quiz.innerHTML ='
<h2> you answered correctly at $
{score}/${quizData.length}
questions.</h2>
<button onclick="location.reload()">Reload</button>
';
}
}
});
http://jsfiddle.net/f4Zkm/213/
HTML
<div ng-app>
<div ng-controller="MyController">
<input type="search" ng-model="search" placeholder="Search...">
<ul>
<li ng-repeat="name in names | filter:filterBySearch">
{{ name }}
</li>
</ul>
</div>
</div>
app.js
function escapeRegExp(string){
return string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}
function MyController($scope) {
$scope.names = [
'Lolita Dipietro',
'Annice Guernsey',
'Gerri Rall',
'Ginette Pinales',
'Lon Rondon',
'Jennine Marcos',
'Roxann Hooser',
'Brendon Loth',
'Ilda Bogdan',
'Jani Fan',
'Grace Soller',
'Everette Costantino',
'Andy Hume',
'Omar Davie',
'Jerrica Hillery',
'Charline Cogar',
'Melda Diorio',
'Rita Abbott',
'Setsuko Minger',
'Aretha Paige'];
$scope.search = '';
var regex;
$scope.$watch('search', function (value) {
regex = new RegExp('\\b' + escapeRegExp(value), 'i');
});
$scope.filterBySearch = function(name) {
if (!$scope.search) return true;
return regex.test(name);
};
}
From the above example, I have been trying to create a wildcard regex search by using a special character '*' but I haven't been able to loop through the array.
Current output: If the input is di, it showing all the related matches.
Required: What I am trying to get is, if the input is di*/*(any input), it should show all the matches as per the given input.
There are a couple issues with your approach. First, you are escaping * in your escape routine, so it can not be used by the client.
Second, you are not anchoring your lines, so the match can occur anywhere.
To fix, remove the asterisk from the escape function :
function escapeRegExp(string){
return string.replace(/([.+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}
Then in your watch function replace * with .* and add line anchors :
$scope.$watch('search', function (value) {
var escaped = escapeRegExp(value);
var formatted = escaped.replace('*', '.*')
if(formatted.indexOf('*') === -1){
formatted = '.*' + formatted + '.*'
}
regex = new RegExp('^' + formatted + '$', 'im');
});
Here is a fiddle
I have two selectors in ERB. They use the Chosen plugin:
<%= select_tag :provinces,
options_for_select(DataHelper::all_provinces_captions.zip(DataHelper::all_provinces_ids)),
{:multiple => true, class: 'chosen-select chzn-select',
:data => {:placeholder => 'Filter Provinces/States'}}
%>
<%= f.select :province_ids,
(DataHelper::all_provinces_captions.zip(DataHelper::all_provinces_ids)),
{ include_blank: true },
{multiple: true, data: {placeholder: 'Filter Provinces/States'} }
%>
I am trying to copy the options from one of the selectors to the other one, while keeping the selected options still selected, however it is not working. Here is the Javascript function I have tried:
var selectedVals = [];
$(".chzn-select").chosen().change(function() {
$("#provinces option:selected").each(function () {
console.log ("this value is " + ($(this).val()));
selectedVals.push($(this).val());
});
$("#education_plan_province_ids").empty();
for (var i = 0; i < selectedVals.length; i++) {
console.log (selectedVals[i] + " selected");
$("#education_plan_province_ids").append($("<option>" + selectedVals[i] + "</option>").attr('selected', true));
}
selectedVals = [];
});
Is there another alternative to attr('selected', true) ?
Here you go:
$(".chzn-select").chosen().change(function() {
$("#education_plan_province_ids").empty();
$("#provinces option:selected").each(function () {
$("#education_plan_province_ids").append($("<option>" + this.value + "</option>").prop('selected', true));
});
});
I am using prop here and getting rid of extra array (which I think is not needed but you can use it if you want). Also you had parenthesis in wrong place for option.
LF way to short my js/jquery function:
$.ajax({ // Start ajax post
..........
success: function (data) { // on Success statment start
..........
//1. Part
$('var#address').text(data.address);
$('var#telephone').text(data.telephone);
$('var#mobile').text(data.mobile);
$('var#fax').text(data.fax);
$('var#email').text(data.email);
$('var#webpage').text(data.webpage);
//2. Part
if (!data.address){ $('p#address').hide(); } else { $('p#address').show(); };
if (!data.telephone){ $('p#telephone').hide(); } else { $('p#telephone').show(); };
if (!data.mobile){ $('p#mobile').hide(); } else { $('p#mobile').show(); };
if (!data.fax){ $('p#fax').hide(); } else { $('p#fax').show(); };
if (!data.email){ $('p#email').hide(); } else { $('p#email').show(); };
if (!data.webpage){ $('p#webpage').hide(); } else { $('p#webpage').show(); };
}, End Ajax post success statement
Here is my html:
<p id="address">Address:<var id="address">Test Street 999 2324233</var></p>
<p id="telephone">Telephone:<var id="telephone">+1 0000009</var></p>
<p id="mobile">Mobile:<var id="mobile">+1 0000009</var></p>
<p id="email">E-mail:<var id="email">info#example</var></p>
<p id="webpage">Web Page:<var id="webpage">www.example.com</var>/p>
How can we reduce the number of selector*(1. part)* and else if the amount (2. part)?
Assuming your object's property names exactly match the spelling of your element ids you can do this:
for (var k in data) {
$('var#' + k).text(data[k]);
$('p#' + k).toggle(!!data[k]);
}
...because .toggle() accepts a boolean to say whether to show or hide. Any properties that don't have a matching element id would have no effect.
Note: your html is invalid if you have multiple elements with the same ids, but it will still work because your selectors specify the tag and id. Still, it might be tidier to just remove the ids from the var elements:
<p id="address">Address:<var>Test Street 999 2324233</var></p>
<!-- etc. -->
With this JS:
$('#' + k).toggle(!!data[k]).find('var').text(data[k]);
And then adding some code to hide any elements that aren't in the returned data object:
$('var').parent('p').hide();
...and putting it all together:
$.ajax({
// other ajax params here
success : function(data) {
$('var').parent('p').hide();
for (var k in data) {
$('#' + k).toggle(!!data[k]).find('var').text(data[k]);
}
}
});
Demo: http://jsfiddle.net/z98cw/1/
["address", "telephone", "mobile", "fax", "email", "webpage"].map(
function(key) {
if (data.hasOwnProperty(key) && !!data[key]) {
$('p#' + key).show();
} else {
$('p#' + key).hide();
}
});
But you should not.
As long as the properties of the object match the id attributes of the p tags you can iterate through the object using the property name as a selector. Also since id attributes are unique, refrain from prefixing the selector with var it is unnecessary.
var data = {
address: "address",
telephone: "telephone",
mobile: "mobile",
fax: "fax",
email: "email",
webpage: "webpage"
};
for(x in data){
var elem = $("#" + x);
if(elem.length == 1){
elem.text(data[x]);
}
}
JS Fiddle: http://jsfiddle.net/3uhx6/
This is what templating systems are created for.
If you insist on using jQuery there is a jQuery plugin: https://github.com/codepb/jquery-template
More:
What Javascript Template Engines you recommend?
I would use javascript templates for this (I've shortened the example a quite a bit, but you should get the gist).
First the template, I love Underscore.js for this so I gonna go ahead and use that.
<% if data.address %>
<p id="address">Address: {%= Test Street 999 2324233 %}</p>
to compile this inside your success function
success: function(data) {
//assuming data is a json that looks like this {'address':'my street'}
var template = _.template(path_to_your_template, data);
$('var#addresscontainer').html(template);
}
Thanks for birukaze and nnnnnn:
With your advice came function;) :
for (var key in data) {
if (data.hasOwnProperty(key) && !!data[key]) {
$('p#' + key).show().find('var').text(data[key]);
} else {
$('p#' + key).hide();
}
};
Now i can avoid for selector with var.
Hi i been trying to achieve this. Need to transform all the numbers 1,2,3,4,5 (or 1956,1986 etc) to arabic numbers ١،٢،٣،٤،٥،٦،٧،٨،٩ I achieved this on a test like this
I have to use the value as >1< so the value="1" wont be affected, cause in db i need to store this as 1, not ١
So, before this the same code using just 1 as value, works great, replace everynumber for its similar in arabic , but also in value="" so this screw all the app. cause in other pages when i get the info i get ١ instead of 1
<script>
$(document).ready(function() {
$("select").html(String($('select').html()).replace(/>1</g, '>١<'));
$("select").html(String($('select').html()).replace(/>2</g, '>٢<'));
$("select").html(String($('select').html()).replace(/>3</g, '>٣<'));
$("select").html(String($('select').html()).replace(/>4</g, '>٤<'));
$("select").html(String($('select').html()).replace(/>5</g, '>٥<'));
$("select").html(String($('select').html()).replace(/>6</g, '>٦<'));
$("select").html(String($('select').html()).replace(/>7</g, '>٧<'));
$("select").html(String($('select').html()).replace(/>8</g, '>٨<'));
$("select").html(String($('select').html()).replace(/>9</g, '>٩<'));
});
</script>
Does anyone has an idea, to make this happend in all body (not just selects) and also without altering the value="" numbers, on inputs, selects, or checks, or radio buttons,
thanks!
Ok just to clarify why i need to do this way.. Im using Rails
Im also using i18n but i couldn´t find a way to "translate" numbers
<div id="altura">
<%= f.label :height %>
<%= f.select :height, Player::HEIGHT.collect {|h| [ t("generales.#{h}"), h ] } , :include_blank => true %> <%= f.select :height_measure, Player::HEIGHT_MEASURE.collect {|h| [ t("generales.#{h}"), h ] } %>
<%= f.select :inches, Player::INCH.collect {|h| [ t("generales.#{h}"), h ] }, {}, :style => (#player.inches.present? && #player.height_measure == 'pies' ? 'display: inline ' : 'display: none') %>
<%= f.label :inches, :id => 'inch_label', :style => (#player.inches.present? && #player.height_measure == 'pies' ? 'display: inline ' : 'display: none') %>
</div>
I really don't understand why you just want to convert the digits, you really should be converting the entire text. But anyway, just for the heck of it, here's a function that does as you want.
Be aware that browsers will recognise sequences of Arabic numbers such as "21 23" and make them read right to left, i.e. "23 21" even though the digits in the number still read left to right (because that's how Arabic numbers work—even though their writing is right to left, their numbers read left to right, just like English).
function replaceDigits(id) {
var el, text;
var arabicCharCodes = {
'0': '1632',
'1': '1633',
'2': '1634',
'3': '1635',
'4': '1636',
'5': '1637',
'6': '1638',
'7': '1639',
'8': '1640',
'9': '1641'
}
// Do not process script elements, add others that have content but
// shouldn't be processed, e.g. maybe object
var elementsToIgnore = { script:'script'};
// If passed a string, expect ID so get element
el = typeof id == 'string'? document.getElementById(id) : id;
// If no element, return
if (!el) return;
var node, childNodes = el.childNodes;
for (var i=0, iLen=childNodes.length; i<iLen; i++) {
node = childNodes[i];
// Recurse over all nodes and only replace the content of text nodes
// in elements that are not in the ignore list
if (node.nodeType == 1 && node.tagName && !(node.tagName in elementsToIgnore)) {
replaceDigits(node);
} else if (node.nodeType == 3) {
text = node.data.split('');
for (var j=0, jLen=text.length; j<jLen; j++) {
if (text[j] in arabicCharCodes) {
text[j] = String.fromCharCode(arabicCharCodes[text[j]]);
}
}
node.data = text.join('');
}
}
}