jquery .change(function) cant call class function - javascript

I am creating a validation script in JavaScript with jQuery and am using the .change() function from jQuery, when the input value is changed I want it to call an object function from itself, displayError(). The function is called from child classes when they are constructed.
The class:
class Input { //this makes a class that all inputs should be assigned to
constructor(input, error) {
this.inputBox = input; //jQuery Object of the input box
this.errorText = error; //jQuery Object of the error text
this.required = this.inputBox.prop("required"); //return true if the inputBox has attribute required and false if not
this.unique = this.inputBox.prop("data-unique"); //USED FOR KNOWING IF NEEDED TO QUERY IN DATABASE
this.errorText.hide(); //hides the error text
}
displayError() { //function that will decide whether the error text needs displaying
var valid = this.auth(); //sees if the value of the input box is valid
//QUERY DB TO SEE IF TAKEN
if (!valid) {
this.errorText.show(); //shows the error text
}
//else if TAKEN && this.unique{SHOW DIFFERENT MESSAGE}
else { //runs if the value is valid
this.errorText.hide(); //hides the error text
}
}
auth() {
let value = this.inputBox.val(); //asssigns the value of the input box to 'value'
if ((!this.required && value == "") || this.isValid(value)) { //if not required the value can be nothing, but if it is required then the value must be validated
return true; //says the value is valid
} else {
return false;
} //says the value is not valid
}
liveErrors() {
this.inputBox.change(function() {
this.displayError()
}); // <--- ISSUE HERE
}
}
All of my class variables are set and are working, I'm not sure if it is because after the .change() I am referencing this in a function which is not set because it is not global variable, if that is the issue I am not sure how to overcome that.
I am very new to JavaScript and OOP, sorry if i have any incorrect terminology or have done something stupid, thanks in advance.

In the anonymous inner function used as the callback for this.inputBox.change, this is the element this.inputBox is pointing to, which is the input element in the dom. You can verify that with a call to console.log( this, typeof this ); in that function before trying to call this.displayError();
You can use jQuery.proxy to call your member function with your chosen context, this.
I stripped down your code and used keypress instead of change for the example snippet, but you can see that it will work to trigger instance methods by typing in the two input fields and seeing that they triggering changes to their instance specific member elements.
Inside of your member function, this should work just as expected.
class Input { //this makes a class that all inputs should be assigned to
constructor(input, error) {
this.inputBox = input; //jQuery Object of the input box
this.errorText = error; //jQuery Object of the error text
}
toggleError() { //function that will decide whether the error text needs displaying
this.errorText.toggle(); //hides the error text
}
liveErrors() {
this.inputBox.keypress($.proxy(this, 'toggleError'));
}
}
let first = new Input($('.first-input'), $('.first-error'));
let second = new Input($('.second-input'), $('.second-error'));
first.liveErrors();
second.liveErrors();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input class="first-input">
<span class="first-error">First!</span>
<br/>
<input class="second-input">
<span class="second-error">Second!</span>

Related

AngularJS: Write inside input box via JS, Do not transfer the value in the JSON

Background: I have an external device (barcode reader) that sends information back to a tablet when the user scans something. I subscribe to that channel and I need the value to be inside the currently focused cell and write it there.
Bug: I can catch the subscription and write the value visually in the Input box, but it never reaches the JSON underneath.
I also tried $scope.$apply() but it did not change anything (maybe I used it wrong).
"Working" Plunker with the problem
$scope.randomClickOnStuff = function() {
// Here Randomely publish stuff with value so we can write it in specific field.
window.setTimeout(function() {
if (!$scope.stopMe) {
vm.objectOtSubscribeTo.publish(channelToUse, Date.now());
$scope.randomClickOnStuff();
} else {
// Stop the loop.
}
}, 1000);
};
var callbackCompleted = function(resultValue) {
// Important code Here
// Code to write in the input box here.
console.log(resultValue);
if (document.activeElement.localName == "input") {
// Option 1:
//--> Work Visually <-- but do not put the value inside the JSON.
document.activeElement.value = resultValue;
$scope.$apply();
// Option 2:
// http://stackoverflow.com/questions/11873627/angularjs-ng-model-binding-not-updating-when-changed-with-jquery
// Problem: The "document.activeElement.attributes['ng-model'].value" is not link with the scope, but with the ng-repeat row. So I have access to the Scope, but not the Row item.
//var binding = document.activeElement.attributes['ng-model'].value;
// Rule: I might not know where the Item is so I cannot do $scope.complexObject[row][binding]
} else {
console.log("not inside a Input box.");
}
};
vm.objectOtSubscribeTo.subscribe(channelToUse, callbackCompleted);
Thanks
One solution would be to keep track of the selected row and cell by setting them on focus of one of the cells
$scope.focusedRow = false;
$scope.focusedCell = false;
$scope.setFocused = (row, cell) => {
$scope.focusedRow = row;
$scope.focusedCell = cell;
};
/* In callback... */
if ($scope.focusedRow !== false && $scope.focusedCell !== false) {
$scope.$apply(
() => $scope.complexObject[$scope.focusedRow]
["cellInTheRow"][$scope.focusedCell] = resultValue
);
}
<input type="text" ng-model="row.cellInTheRow[key]"
ng-focus="setFocused(rowKey, key)" ng-blur="setFocused(false, false)">
Example: https://plnkr.co/edit/och5PoepJuRde0oONIjm?p=preview

Popup - if user enters bad input, how can I get it to error on submit

I have a popup on my page that has a typeahead input on it. Right now you can type garbage and click submit and it lets you. I'm trying to write code that will throw an error on the popup if you type something that isn't included in the typeahead options and it won't let you submit it until you fix it. Here is my code, it is for making a school schedule that has classes in the typeahead dropdown.
var schedule = schedule.content.get();
var validClasses = Fp.filter(schedule.classes, function (class) { return !class.passed; }),
inputClasses = $('.optimizeViaClasses input.className').map(function () { return $(this).val(); }),
isErrorForValidClasses = Fp.all(inputClasses, function (inputClass) { return Fp.contains(validClasses, inputClass); });
if(validClasses !== inputClasses){
$errorMessage.text('Your selection does not match the class(es) in the current schedule!');
$errorMessage.show();
}
Right now if you enter garbage in the input field, this will throw an error but still let the user submit. How can I stop the user from submitting until the input is correct?
Here is my button:
$submitBtn.on('click', function(event){
if(inputParameters() !== false){
$myPopUp= $modal.find('#myData').detach()[0];
}
event.preventDefault();
});
and I checked the output of inputClasses in the Google developer console, it outputs the class and a prevObject. I just need the class...
Let javascript return either True or false and if the popup comes out return false other wise true.
For instance if it get into if return false other wise true.
since you modified your code i suppose you might want to try this instead:
http://api.jquery.com/event.stoppropagation/
also you might want to be doing something along the lines of this if stoppropagation does not result in the desired effect:
$("#formid").on("submit",function(e){
// declare isValid outside of this and set it in your validation function or call it inside this and check for that.
if(isValid) {
e.stopPropagation();
}
});
at least that's how i went about solving such issues usually. i hope it helps.
got it. the error i had was throwing an error.
var schedule = schedule.content.get(),
validClasses = Fp.filter(schedule.classes, function (class) { return !class.passed; }),
inputClasses = $('.optimizeViaClasses input.className').map(function () { return $(this).val(); }),
actualValidClasses = Fp.pluck(validClasses, 'className');
$.each(inputClasses , function(index, value){
if($.inArray(value, actualValidClasses ) === -1){
$errorMessage.text('Your selection does not match the class(es) in the current schedule!');
$errorMessage.show();
error = true;
return false;
}
});

Javascript - set focus after alert message

I'm tryng to focus on the same element when validation fail. Here's my HTML code :
<input
id="potatoes" name="potatoes" value="" type="text" class="tooltip"
onblur="Validate('potatoes')" autocomplete='off'>
and here's my javascript code :
function Validate(id) {
var errors = {
potatoes : 'enter potatoes',
hamburgers : 'enter'
};
if (document.getElementById(id).value === '') {
if (id in errors) {
alert(errors[id]);
//setTimeout(function(){document.getElementById(id).focus();}, 1);
}
}
}
I've tried to set focus using .focus() method but it doesn't work. I've read that it might depend on "onblur" in HTML, when I call my function Validate(), so i've tried to change it but nothing worked till now.
There is a problem here. This code is going in loop. When 'focus' is triggered, the function Validate is called again, showing another alert dialog.
That's a working code
HTML
<input id="potatoes" name="potatoes" value="" type="text" class="tooltip" onblur="Validate(this)" autocomplete='off'>
Javascript
var validating = false; //<-- IMPORTANT
function Validate(element) {
var id = element.id;
var errors = {
potatoes : 'enter potatoes',
hamburgers : 'enter'
};
if (document.getElementById(id).value === '') {
if (id in errors) {
if(validating == false) {
validating = true
alert(errors[id]);
setTimeout(function(){
document.getElementById(id).focus();
validating = false;
}, 1);
}
}
}
}
In the html I'm passing this, doing so I'm passing the element and in the Validate function you can access to the id just calling
var id = element.id;
For the focus problem (caused by a loop problem) as you can see I'm using a validating variable to know when is validating when is not. This let Validate function avoids to go in loop.
So:
1) Define a validating var outside the Validate function and set it to false.
2) Fire the focus and alert only if validating is false, and after that set it to true
The javascript function alert(string) is synchronous. The script is paused while the user is reacting to the alerted message. There is no need to do something special. The following snippet should work:
alert(errors[id]);
document.getElementById(id).focus();
The element got focus directly after the user has submitted the alerted message.
You can use jQuery like this:
setTimeout(function() {$('#yourInputId').focus();},1);

jquery check values in form

I have two inputs where I am checking to make sure that they are not empty before the form submits.
My issue is that it only validates #from_date. Is the issue that .val will only check the last id in the list?
$('#submitDates').click(function () {
// Get the fields you want to validate
var name = $("#to_date, #from_date");
// Check if field is empty or not
if (name.val()=='') {
alert ('Please Select Dates')
return false;
} ;
});
});
Any specific reason you're hooking on .click and not .submit?
You can iterate through the selected elements and check for a violating element using .each
var found = false;
$("#to_date, #from_date").each(function(i,name){
// Check if field is empty or not
if (!found && $(name).val()=='') {
alert ('Please Select Dates')
found = true;
} ;
});
return !found;
In your example var name = $("#to_date, #from_date"); is giving you a collection of two inputs and by doing if (name.val()=='') jQuery is checking only the first element in the collection, so it's not working. You may try this
$('#submitDates').click(function () {
var name = $("#to_date, #from_date");
if ( name[0].value == '' || name[1].value == '' ) {
alert ('Please Select Dates');
return false;
}
});
In the above example name[0].value refers to the first element and name[1].value refers to the second element. If you want to use jQuery's val() method then you can use it like $(name[0]).val() and $(name[1]).val().
Also you should consider to use submit event of the form instead of button's click event.

Why is my .blur() code only working on second blur?

I have an input, when the user enters something, my script sends the info over to a php script, which returns whether or not the entered text can be used.
If the text can not be used, it disables the submit button and adds a class to the reult text.
The problem have is strange, the ajax works, the result is returned, but the button disabling and adding of the class doesn't happen unless you focus and blur the input a second time.
Here is my code:
$('#alias').blur(function() {
if ($('#alias').val()) {
var aliascheck = $('#alias').val();
$(".aliascheck").load('checkalias.php?alias='+aliascheck);
var result = $('.aliascheck').text();
if (result.indexOf("Taken") != -1) {
$('#shorten').attr("disabled","disabled");
$('.aliascheck').addClass('error');
} else {
$('#shorten').removeAttr("disabled");
$('.aliascheck').removeClass('error');
}
}
});
The code is live here: http://markhenderson.ws/dev/tmtmu/
To replicate the "taken" event, enter "taken" as the alias. Any thing else will return available.
Does anyone know why this is happening?
Thanks
You need to put the code after the .load call into a callback function of the async call.
Something like:
$('#alias').blur(function() {
if ($('#alias').val()) {
var aliascheck = $('#alias').val();
$(".aliascheck").load('checkalias.php?alias='+aliascheck, function() {
var result = $('.aliascheck').text();
if (result.indexOf("Taken") != -1) {
$('#shorten').attr("disabled","disabled");
$('.aliascheck').addClass('error');
} else {
$('#shorten').removeAttr("disabled");
$('.aliascheck').removeClass('error');
}
});
}
});

Categories