I want to restrict users decimal inputs when configured as decimals in Numerictextbox. I'm using knockoutjs to observe the data from numerictextbox. When the user enters more decimal it's automatically updated in knockout, but in control it shows only the configured decimals.
Decimals are set dynamically to kendo numerictextbox, so I need to restrict user input decimals when its more of defined decimals. When user enter in a number of decimals knockout updates that value
One example is if I set decimals to 2. When the user enters 56.2456 knockout updates this value in the model, and after the cursor moves to the next control numerictextbox shows 56.25. I want to update this value into the model and need to restrict user entering more then 2 decimals.
How can I apply this restriction?
You can do key press event of Text box as code below.
$("#txtXZY").kendoNumericTextBox({
format: "#.00 \\%",
min: 0,
decimals: 2,
max: 100,
step: 1,
spinners: IsSpinner
});
$("#txtXZY").bind("keypress", function (e) {
if (IsTextSelected(this) == false && e.keyCode !== kendo.keys.ENTER) {
var character = String.fromCharCode(e.keyCode)
var newValue = this.value + character;
if (isNaN(newValue) || parseFloat(newValue) * 100 % 1 > 0) {
e.preventDefault();
return false;
}
if (parseFloat(newValue) > 100) {
e.preventDefault();
return false;
}
}
});
function IsTextSelected(input) {
if (typeof input.selectionStart == "number") {
return input.selectionStart == 0 && input.selectionEnd == input.value.length;
} else if (typeof document.selection != "undefined") {
input.focus();
return document.selection.createRange().text == input.value;
}
}
Related
I need to add ajax validations in the checkout page when the users click on the Continue button in each checkout step. Does anyone know if this is possible?
I need to send the Cart object, Address, items, etc. The idea is, the users are unable to continue, if they fail the validation.
You can only do this if you are on Shopify Plus. You cannot inject Javascript into checkout for the very good reason that you'd probably break it! It is a finely tuned machine, so the most you can do usually is change some css classes.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
If you have Shopify Plus, then you can insert your js form validation.
Also you have to replace the given input id with you custom id. After which, you can insert, check and get data from input fields
Below is script for phone number validation
$("#checkout_shipping_address_phone").attr("id","checkout_shipping_address_phone_clone");
document.getElementById('checkout_shipping_address_phone_clone').setAttribute('maxlength','10');
document.getElementById('checkout_shipping_address_phone_clone').setAttribute('max-length','10');
// document.getElementById('checkout_shipping_address_phone').setAttribute('type','number');
// document.getElementById('checkout_shipping_address_phone').setAttribute('minlength','10');
// document.getElementById('checkout_shipping_address_phone').setAttribute('data-minlength','10');
let mobileBtn = document.getElementById('checkout_shipping_address_phone_clone');
mobileBtn.removeAttribute('aria-required');
mobileBtn.removeAttribute('data-phone-formatter-country-select');
mobileBtn.removeAttribute('data-phone-formatter');
mobileBtn.removeAttribute('autocomplete');
mobileBtn.setAttribute("onkeypress","return isNumber(event)");
mobileBtn.type='text';
console.log("aaa");
function isNumber(evt){
evt = (evt) ? evt : window.event;
var charCode = (evt.which) ? evt.which : evt.keyCode;
if (charCode > 31 && (charCode < 48 || charCode > 57)) {
return false;
}
return true;
}
$("body").on("click","#continue_button",function(){
var hh = $('#checkout_shipping_address_phone_clone').val();
if(hh.length==10){
console.log('dbcjhsdvjhdsvhjsjh');
$("#error_msgehh").remove();
$('#continue_button').attr('type','submit');
$('#continue_button').css('opacity','1');
}
else{
console.log(hh.length);
$('#continue_button').css('opacity','.5');
$("#error_msgehh").remove();
$('#checkout_shipping_address_phone_clone').parent().after().append('<p id="error_msgehh" style="color:red;">Enter 10 Digit Phone Number</p>');
$('#continue_button').attr('type','button');
}
});
$('#checkout_shipping_address_phone_clone').attr('maxlength','10');
$('#checkout_shipping_address_phone_clone').attr('max-length','10');
$("body").on("keyup mouseenter mouseleave","#checkout_shipping_address_phone_clone",function(){
var hh = $(this).val();
const regexExp = /^[6-9]$/gi;
let firstChar = regexExp.test(hh[0]); // dont allow 0,1,2,3,4,5 digits at first place
if(!firstChar){
var v ='';
$('#checkout_shipping_address_phone_clone').val(v);
}
});
$("body").on("keyup mouseenter mouseleave",".field__input-wrapper input",function(){
var hh = $('#checkout_shipping_address_phone_clone').val();
console.log('hover');
const regexExp = /^[6-9]$/gi;
let firstChar = regexExp.test(hh[0]); // dont allow 0,1,2,3,4,5 digits at first place
if(!firstChar){
var v ='';
$('#checkout_shipping_address_phone_clone').val(v);
}
});
// console.log("bbbaaa");
// });
I need to clear up what may be a potential misunderstanding between me and the recaptcha library.
All of the examples that I have seen from searching around and finding YouTube videos of the v3 implementation have been attaching the recaptcha ready/execute functions within the context of a <form>... but I am trying to use reCaptcha outside the context of a <form> in the following way:
A user enters a name or a portion of their name into a search box
The frontend, after a delay of input or the enter key, gets names in the system which match this input (partial or full)
The results are loaded into a drop-down that auto-populates.
The user selects the appropriate name through either clicking or arrowing down, and this searches for specific data about that user.
If I can figure out how to get the reCaptcha token to take place on the name dropdown search, I will be able to extend that solution to the fourth point... but I am afraid that it may not be possible.
All code below is JavaScript:
Relevant Bits
Listener on search field:
$(".web-search-content").on("keyup", ".searchField", function(e) {
if (
e.keyCode != 40 &&
e.keyCode != 38 &&
e.keyCode != 13 &&
e.keyCode != 27
) {
delayCall($(this), 800, nameSearch, e);
} else if (e.keyCode == 27) {
$(".name-search-results").remove();
}
});
nameSearch function:
function nameSearch(obj, e) {
if (!e) {
e = window.event;
}
var container = $(".name-search-results");
if (
e.keyCode != 40 &&
e.keyCode != 38 &&
e.keyCode != 13 &&
e.keyCode != 27
) {
var field = obj;
var value = field.val();
if (value != undefined && value.length > 0) {
var captchaToken = "";
grecaptcha.execute('<REDACTED>', {action: 'webSearch/nameSearch'}).then(function(token) {
captchaToken = token;
console.log(captchaToken);
document.getElementById("g-recaptcha-response").value = token;
})
$.post("../webSearch/nameSearch", { query: value, captchaToken: captchaToken }, function(resp) {
showNameResults(resp);
});
} else {
container.remove();
}
}
}
Can someone confirm that reCaptcha v3 must be used within the context of a form, or can it handle events like this... and if so, how?
reCAPTCHA v3 is not tied to a form submission. From the docs:
reCAPTCHA v3 will never interrupt your users, so you can run it whenever you like without affecting conversion. reCAPTCHA works best when it has the most context about interactions with your site, which comes from seeing both legitimate and abusive behavior. For this reason, we recommend including reCAPTCHA verification on forms or actions as well as in the background of pages for analytics.
Note: You can execute reCAPTCHA as many times as you'd like with different actions on the same page.
So, you don't need to wait for the user to submit the form to run reCAPTCHA. Instead, you can make the call in the background for different actions across the site. Store the returned score and then check that on form submission to decide what action you want to take.
// Decide what score you want to allow as a pass
const threshold = 0.5;
// Set up a variable
let score = null;
// Call reCAPTCHA on page load
grecaptcha.ready(function () {
grecaptcha.execute('[redacted]', { action: 'pages/search' }).then(function (token) {
// Create an endpoint on your server to validate the token and return the score
fetch('/recaptcha-verify?action=pages/search&token=' + token).then(function (response) {
response.json().then(function (data) {
score = data.score;
});
});
});
});
// Later, e.g. in the form submission just check if the score is above the threshold
if (score >= threshold) {
// success
submitForm();
} else {
// score too low
doSomethingElse();
}
This is the approach used here:
https://recaptcha-demo.appspot.com/recaptcha-v3-request-scores.php
https://github.com/google/recaptcha/blob/master/examples/recaptcha-v3-request-scores.php
I'm trying to limit the number of words allowed in a summernote.
example, I want to limit up to 50 words only.
Do you have any idea?
$(document).ready(function() {
$('#summernote').summernote({
height: 20,
});
});
Thought I would contribute to this post as this helped me arrive to my desired solution. It seems the suggested answer has not been accepted.
I created a variable for maxLength and the following is how I configured summernote callbacks. Please note the version of summernote I am using has the editing area as .note-editable. The solution below is typescript and I have a span that I target which displays the remaining character count.
callbacks: {
onKeydown(e) {
// The text method will ignore HTML tags and preserve non-breaking
// space allowing for a true character count
let content: string = $('.note-editable').text();
// This checks if the character is alphanumeric (i.e. not a backspace or return key)
let isCharacter: boolean = (/[a-zA-Z0-9-_ ]/.test(String.fromCharCode(e.keyCode)));
// If the current content length is at max, preventDefault will disallow
// any more characters
if (isCharacter) {
if (content.length >= maxLength) {
e.preventDefault();
}
}
},
onKeyup(e) {
// After the result of checking the character and max length exceeded,
// take the resulting count and determine and display characters remaining
let content: string = $('.note-editable').text();
let charactersRemaining: number = maxLength - content.length;
$('#SomeDivId span').text(charactersRemaining);
}
var maxwords = 100;
$(".summernote").summernote({
height: '200px',
callbacks: {
onKeydown: function (e) {
var t = e.currentTarget.innerText;
var words = t.split(" ");
if (words.length >= maxwords) {
//delete key
if (e.keyCode != 8)
e.preventDefault();
// add other keys ...
}
},
onKeyup: function(e) {
var t = e.currentTarget.innerText;
var words = t.split(" ");
if (words.length >= maxwords) {
//delete key
if (e.keyCode != 8)
e.preventDefault();
// add other keys ...
}
},
onPaste: function(e) {
var t = e.currentTarget.innerText;
var bufferText = ((e.originalEvent || e).clipboardData ||
window.clipboardData).getData('Text');
e.preventDefault();
var all = t + bufferText;
var words = all.split(" ");
var array = words.slice(0, maxwords)
document.execCommand('insertText', false, array.join(" "));
}
}
});
Words vs Characters:
I suggest that you decide on the number of characters rather than words because that is easy and consistent even for the user.
Summernote creates contenteditable divlike below:
With this knowledge and using the below answer, you can achieve a solution where you can restrict the number of characters:
Limiting Number of Characters in a ContentEditable div
I am familiar with the Google Apps script DataValidation object. To get and set validation criteria. But how to tell programatically if a cell value is actually valid. So I can see the little red validation fail message in the spreadsheet but can the fact the cell is currently failing validation be picked up thru code?
I have tried to see if there is a cell property that tells you this but there is not. Also I looked for some sort of DataValidation "validate" method - i.e. test a value against validation rules, but nothing there either
Any ideas? Is this possible??
Specific answer to your question, there is no method within Google Apps Script that will return the validity of a Range such as .isValid(). As you state, you could reverse engineer a programatic one using Range.getDataValidations() and then parsing the results of that in order to validate again the values of a Range.getValues() call.
It's a good suggestion. I've added a feature request to the issue tracker -> Add a Star to vote it up.
I've created a workaround for this issue that works in a very ugly -technically said- and slightly undetermined way.
About the workaround:
It works based on the experience that the web browser implementation of catch() function allows to access thrown errors from the Google's JS code parts.
In case an invalid input into a cell is rejected by a validation rule then the system will display an error message that is catchable by the user written GAS. In order to make it work first the reject value has to be set on the specified cell then its vale has to be re-entered (modified) then -right after this- calling the getDataValidation() built in function allows the user to catch the necessary error.
Only single cells can be tested with this method as setCellValues() ignores any data validation restriction (as of today).
Disadvantages:
The validity won't be necessarily re-checked for this function:
it calls a cell validation function right after the value is inserted into the cell.
Therefore the result of this function might be faulty.
The code messes up the history as cells will be changed - in case they are
valid.
I've tested it successfully on both Firefox and Chromium.
function getCellValidity(cell) {
var origValidRule = cell.getDataValidation();
if (origValidRule == null || ! (cell.getNumRows() == cell.getNumColumns() == 1)) {
return null;
}
var cell_value = cell.getValue();
if (cell_value === '') return true; // empty cell is always valid
var is_valid = true;
var cell_formula = cell.getFormula();
// Storing and checking if cell validation is set to allow invalid input with a warning or reject it
var reject_invalid = ! origValidRule.getAllowInvalid();
// If invalid value is allowed (just warning), then changing validation to reject it
// IMPORTANT: this will not throw an error!
if (! reject_invalid) {
var rejectValidRule = origValidRule.copy().setAllowInvalid(false).build();
cell.setDataValidation(rejectValidRule);
}
// Re-entering value or formula into the cell itself
var cell_formula = cell.getFormula();
if (cell_formula !== '') {
cell.setFormula(cell_formula);
} else {
cell.setValue(cell_value);
}
try {
var tempValidRule = cell.getDataValidation();
} catch(e) {
// Exception: The data that you entered in cell XY violates the data validation rules set on this cell.
// where XY is the A1 style address of the cell
is_valid = false;
}
// Restoring original rule
if (rejectValidRule != null) {
cell.setDataValidation(origValidRule.copy().setAllowInvalid(true).build());
}
return is_valid;
}
I still recommend starring the above Google bug report opened by Jonathon.
I'm using this solution. Simple to learn and fast to use! You may need to adapt this code for your needs. Hope you enjoy
function test_corr(link,name) {
var ss = SpreadsheetApp.openByUrl(link).getSheetByName(name);
var values = ss.getRange(2,3,200,1).getValues();
var types = ss.getRange(2,3,200,1).getDataValidations()
var ans
for (var i = 0; i < types.length; i++) {
if (types[i][0] != null){
var type = types[i][0].getCriteriaType()
var dval_values = types[i][0].getCriteriaValues()
ans = false
if (type == "VALUE_IN_LIST") {
for (var j = 0; j < dval_values[0].length; j++) {
if (dval_values[0][j] == values[i][0]) { ans = true }
}
} else if (type == "NUMBER_BETWEEN") {
if (values[i][0] >= dval_values[0] && values[i][0] <= dval_values[1]) { ans = true }
} else if (type == "CHECKBOX") {
if (values[i][0] == "Да" || values[i][0] == "Нет") { ans = true }
}
if (!ans) { return false }
}
}
return true;
}
If I will add new row and I will enable automatic editing newly added row, then I want to perform validation and save row by ENTER button, BUT I don't want to restore row by ESC button. Because I set required: true by all fields and If newly added row will be to have empty at least one field, then ESC button (restoreRow) causes inconsistency my data, because will not be performed validation and newly added row will be to have empty fields. Although I set required: true.
The problem is that After added new row I always want to validate the edited row before saving, but ESC button causes restoreRow. For normal editing causes by doubliClick I want use ESC for restore row and ENTER for save row.
My code is generated from coffeescript
$("#add-row").click((function(_this) {
return function(e) {
e.preventDefault();
return _this.saveEditingRow(function() {
var dataIds;
_this.table.jqGrid("addRowData", void 0, "last");
dataIds = _this.table.jqGrid("getDataIDs");
if (dataIds.length > 0) {
return _this.table.jqGrid("editRow", dataIds[dataIds.length - 1], {
keys: true,
url: "clientArray",
aftersavefunc: function(rowId) {
return retypeColumnValues.call(table, rowId);
}
});
}
});
};
})(this));
Table.prototype.saveEditingRow = function(successfunc, errorfunc) {
var i, result, savedRows, success, _i, _ref;
savedRows = this.table.jqGrid("getGridParam", "savedRow");
success = true;
for (i = _i = 0, _ref = savedRows.length; _i < _ref; i = _i += 1) {
if (savedRows.length > 0) {
result = this.table.jqGrid("saveRow", savedRows[i].id, {
url: "clientArray"
});
if (!result && success) {
success = false;
}
}
}
if (success) {
return typeof successfunc === "function" ? successfunc() : void 0;
} else {
return typeof errorfunc === "function" ? errorfunc() : void 0;
}
};
If it will be necessary, I will fill all code in coffeescript.
I agree that it's a problem because the option keys: true register keydown event handler which process both Enter and Esc. You can't just inform jqGrid to process Enter, but don't process Esc.
If you don't call restoreRow in your code then you could probably salve your problem by usage of beforeCancelRow callback which you could define in $.jgrid.inlineEdit.
$.extend(true, $.jgrid.inlineEdit, {
beforeCancelRow: function () { // the parameters options and rowid can be used
return false;
}
});
The code above will don't allows restoreRow at all. You can modify the code by including some validations.
One more options which you have: don't use keys: true, but register your own keydown handler on all <input> and <select> fields in the editing row. You can do this inside of oneditfunc callback. See the source code of keydown handler used by jqGrid. You need just call of saveRow in case of e.keyCode === 13. The required rowid you can either get from the outer scope (if you do this inside of oneditfunc) or to get it from e.target: $(e.target).closest("tr.jqgrow").attr("id").
One more option: you can add some class like jqgrid-new-row (it's the class used by addRow method) to the row (<tr>) directly after call of addRowData ($("#" + dataIds[dataIds.length - 1]).addClass("jqgrid-new-row")). You should add afterrestorefunc callback to editRow which you call. Inside of the afterrestorefunc you can test whether the row has jqgrid-new-row class and call delRowData row in the case. By the way if you add the class with jqgrid-new-row name (or to use addRow instead of addRowData) then deleting of canceled row will be done automatically by restoreRow (see the code fragment).
You can even do this unconditionally without any tests for the class jqgrid-new-row if the above code work only in case of editing of new added row. So the call of editRow could be like below
return _this.table.jqGrid("editRow", dataIds[dataIds.length - 1], {
keys: true,
url: "clientArray",
aftersavefunc: function(rowId) {
return retypeColumnValues.call(table, rowId);
},
afterrestorefunc: function(rowId) {
_this.table.jqGrid("delRowData", rowId); // delete after cancel editing
}
});