I'm trying to add a validator to a form field in ExtJS 6.5.3.57 Classic or Modern. I thought from reading various posts that this should work, but when I run myField.isValid() it always returns true, and I don't see my console.log() statement firing so I have to assume my function isn't getting called.
{xtype: numberfield,
name: 'myField',
validator: function(field){
console.log('testing my validator');
return false;
}
}
I also tried this as I wasn't sure if it was validator or validators
{xtype: numberfield,
name: 'myField',
validators: {
fn: function(field){
console.log('testing my validator');
return false;
}
}
}
Am I wrong in thinking this should work?
Here's a fiddle showing that the top field in the login form which has a validator on it but never seems to log a message to the screen or console. https://fiddle.sencha.com/#fiddle/2eoa
The second example you gave is valid, I've made a working fiddle:
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.Viewport.add({
xtype: 'textfield',
validators: {
fn: function(v) {
return v === 'abc' || 'Value must be abc'
}
}
});
}
});
I have implemented a custom validation function using the example referenced in the SimpleSchema documentation for validating the uniqueness of a username. In the example, an asynchronous call is made and a custom validation message is displayed if the username is found to already exist.
There is a note, that indicates that if all of the form fields are valid, the form will be submitted, however user creation will fail due to the "unique: true" requirement specified in the schema. Here is the relevant portion of the code from the example docs:
username: {
type: String,
regEx: /^[a-z0-9A-Z_]{3,15}$/,
unique: true,
custom: function () {
if (Meteor.isClient && this.isSet) {
Meteor.call("accountsIsUsernameAvailable", this.value, function (error, result) {
if (!result) {
Meteor.users.simpleSchema().namedContext("createUserForm").addInvalidKeys([{name: "username", type: "notUnique"}]);
}
});
}
}
}
In my case, I have the code working where I am testing if an activation code is valid, I even get the interface to display the error, however since there is no other "schema" failure, the form submits, despite the invalid response... do I need to manually prevent form submission (i.e. using jQuery), or is there something in SimpleSchema I should use instead?
activationCode: {
type: String,
label: "Activation Code",
max: 200,
min: 10,
regEx: /^(?=.*[A-Z])(?=.*\d).+$/,
custom: function() {
if (Meteor.isClient && this.isSet) {
Meteor.call("validateActivationCode", this.value, function(error, result) {
if (result && !result.isValid) {
Clients.simpleSchema().namedContext("signupForm").addInvalidKeys([{
name: "activationCode",
type: "notValid"
}]);
return false;
}
});
}
}
}
Thank You
I'm having an issue similar to the issues reported both here and here, with a only a few changes in how my form data is loaded.
The solution provided in the second link seemingly resolves my issue, but removing the show/hide scaling effects should not be required in order for CKEditor to instantiate properly. There's bound to be a much better alternative to resolving this conflict.
My issue:
When I open my page, and click the edit button, a jQueryUI Dialog pops up, loads its data via ajax, and then I attempt to replace the textarea added to the dialog with a CKEditor instance. The first time I load the page, the dialog works without a hitch. I'm able to modify the data within the editor, save my form data, and get on with life. However, if I close the dialog, then open it again, the editor is no longer enabled. The buttons still have hover effects, and are clickable, but do nothing. The text area of the editor is disabled and set to "style: visibility: hidden; display: none;". Nearly all the information I can find regarding this issue is from many years ago, and the fixes involve using functions/techniques that no longer exist or are applicable.
Control Flow
I open the page containing a text link 'Edit Update', which calls my Javascript function openEditTicketUpdateDialog.
function openEditTicketUpdateDialog(tup_id, url)
{
simplePost(null, url, new Callback
(
function onSuccess(data)
{
$('#editticketupdatedialog').dialog('option', 'buttons',
[
{
text: 'Save Edits',
click: function()
{
// Save the Update info
var formData = {
tup_update: CKEDITOR.instances.tup_update_edit.getData(),
tup_internal: +$('#tup_internal_edit').is(":checked"),
tup_important: +$('#tup_important_edit').is(":checked")
};
simplePost(formData, data['submitRoute'], new Callback
(
function onSuccess(data)
{
$('#update-' + tup_id).html(data.input['tup_update']);
$('#updateflags-' + tup_id).html(data.flags);
$('#editticketupdatedialog').dialog('close');
},
function onFail(errors)
{
console.log(errors);
}
));
}
},
{
text: 'Cancel',
click: function()
{
$(this).dialog("close");
}
}
]);
$('#editticketupdatedialog').dialog('option', 'title', data['title']);
$('#editticketupdatedialog').html(data['view']);
$('#editticketupdatedialog').dialog('open');
destroyEditor('tup_update_edit');
console.log('CKEDITOR.status: ' + CKEDITOR.status);
createEditor('tup_update_edit');
},
function onFail(errors)
{
console.log(errors);
}
));
}
This function uses three helper functions, simplePost, destroyEditor and createEditor.
function simplePost(data, url, callback)
{
post(data, url, true, false, callback);
}
function createEditor(name)
{
console.log('Create editor: ' + name);
console.log('Current Instance: ');
console.log(CKEDITOR.instances.name);
if (CKEDITOR.status == 'loaded')
{
CKEDITOR.replace(name,
{
customConfig: '/js/ckeditor/custom/configurations/standard_config.js'
});
}
else
{
CKEDITOR.on('load', createEditor(name));
CKEDITOR.loadFullCore && CKEDITOR.loadFullCore();
}
console.log('After instance created: ');
var instance = CKEDITOR.instances.name;
console.log(instance);
}
function destroyEditor(name)
{
console.log('Destroy editor: ' + name);
console.log('Current Instance: ');
console.log(CKEDITOR.instances.name);
if (CKEDITOR.instances.name)
{
console.log('Instance exists - destroying...');
CKEDITOR.instances.name.destroy();
$('#' + name).off().remove();
}
console.log('After instance removed: ');
var instance = CKEDITOR.instances.name;
console.log(instance);
}
This method of creating a CKEditor instance was gathered from here. This method of destroying a CKEditor instance was gathered from here.
As you can see, openEditTicketUpdateDialog fires an AJAX call to my getEditUpdateForm function through Laravel routes.
public function getEditUpdateForm($tup_id, $update_number)
{
$update = Update::find($tup_id);
$data = [
'title' => 'Editing update #' . $update_number . ' of ticket #' . $update->tup_ticket,
'view' => View::make('tickets.ticketupdate-edit')
->with('update', $update)
->render(),
'submitRoute' => route('tickets/update/submit', $tup_id)
];
return Response::json(array('status' => 1, 'data' => $data));
}
From here, a status of 1 is returned, and the onSuccess function is called. I've attempted to add the create/delete calls before the $('#editticketupdatedialog').dialog('open'); call, but to no avail. I've also tried multiple other solutions that I've found surfacing, which involve hacked implementations of jQueryUI's Dialog functions and attributes: _allowInteraction and moveToTop. I was originally successful in resolving this issue the first time it arose by calling this function before doing a CKEDITOR.replace:
function enableCKEditorInDialog()
{
$.widget( "ui.dialog", $.ui.dialog, {
/**
* jQuery UI v1.11+ fix to accommodate CKEditor (and other iframed content) inside a dialog
* #see http://bugs.jqueryui.com/ticket/9087
* #see http://dev.ckeditor.com/ticket/10269
*/
_allowInteraction: function( event ) {
return this._super( event ) ||
// addresses general interaction issues with iframes inside a dialog
event.target.ownerDocument !== this.document[ 0 ] ||
// addresses interaction issues with CKEditor's dialog windows and iframe-based dropdowns in IE
!!$( event.target ).closest( ".cke_dialog, .cke_dialog_background_cover, .cke" ).length;
}
});
}
After updating to Laravel 5, and making a few other changes serverside, this fix no longer works. I have been successful in resolving my issue by removing the show/hide properties from my dialog. I would very much prefer not to have to remove these properties, as half the reasoning for having the dialog is the aesthetics of an animation. Here is my dialog initialization.
$('#editticketupdatedialog').dialog({
modal: true,
draggable: false,
minWidth: 722,
autoOpen: false,
show:
{
effect: "scale",
duration: 200
},
hide:
{
effect: "scale",
duration: 200
},
closeOnEscape: true
});
When I have these animations enabled, the first time I use the dialog, it works perfectly. The second time, I receive the error TypeError: this.getWindow(...).$ is undefined - ckeditor.js:83:18 in the JS console, which refers to this line:
function(a)
{
var d = this.getWindow().$.getComputedStyle(this.$,null);
return d ? d.getPropertyValue(a) : ""
}
Recap
My main goal here is to find a fix for this issue, without having to remove the jQueryUI Dialog animation. I am unsure whom to point fingers at, as I really can't determine if the issue lies in CKEditor, jQueryUI or my implementation.
I finally found a solution that works in my case. losnir updated the outdated solution to a post here, and adding the open function to my dialog initialization resolved my issue.
My initialization is as follows:
$('#editticketupdatedialog').dialog({
modal: true,
draggable: false,
minWidth: 722,
autoOpen: false,
show:
{
effect: "scale",
duration: 200
},
hide:
{
effect: "scale",
duration: 200
},
closeOnEscape: true,
open: function()
{
$(this).parent().promise().done(function ()
{
destroyEditor('tup_update_edit');
console.log('CKEDITOR.status: ' + CKEDITOR.status);
createEditor('tup_update_edit');
});
}
});
When I attempt to create a method to use the methods provided in the additional-methods.js file I get the intended validation. However, if the user inputs a wrong value, instead of displaying the exception defined in the additional-methods.js file, the user sees the title of the current element, which is currently being used for type-hinting.
My JavaScript looks like this:
//setup input validation
validator = form.validate({
rules: {
city: {
required: true,
lettersonly: true
}
}
});
$('input, textarea').blur(function(){
element = $(this);
// if the user gave no value then show the this field is required
if(element.val() == element.attr('title')){
refreshError(element, 'This field is required');
}else if(element.val() == '') { //if the value is empty then check if it was required, also check if it had an input hint
//if the element is required display the error message
if(element.hasClass('required')){
refreshError(element, 'This field is required');
}
//if the title exists then we assume it is the input hint
if(element.attr('title') != ''){
element.val(element.attr('title'));
element.addClass('inputHint');
}
}else{
//if we got input validate it
response = element.valid();
//if we got an error clear the old one(conditional on existance), and display the new one. Otherwise clear any old error
if(!response){
this.defaultShowErrors();
}else{
errorId = element.attr('id')+'Error';
$('#'+errorId).remove();
}
}
});
With the relevant part of the form being:
<label for="city">City:</label>
<input type="text" name="city" id="city" class="required inputHint" title="Your city here" />
Any ideas as to what I am doing wrong? I am using the 1.9.0 version of the jQuery Validator plugin
NB: I thought I had hit the nail on the head after reading: addMethod() of jQuery validation plugin display error from title attribute but after trying:
//setup input validation
validator = form.validate({
rules: {
city: {
required: true,
lettersonly: true
}
},
messages: {
city: {
lettersonly: "you must give a valid city"
}
}
});
I found that nothing changed.
I just ran into this error and came across the ignoreTitle option:
//setup input validation
validator = form.validate({
ignoreTitle: true,
rules: {
city: {
required: true,
lettersonly: true
}
},
messages: {
city: {
lettersonly: "you must give a valid city"
}
}
});
According to the documentation for the JQuery validation plugin:
the validation is lazy: Before submitting the form for the first time, the user can tab through fields without getting annoying messages
Is there any way to display the messages as the user tabs through the form?
Cheers
You can override the default onfocusout to do more eager/pre-submit validation you want, like this:
$(function() {
$("form").validate({
rules: { ...rules... },
messages: { ...messages... },
onfocusout: function(element) { $(element).valid(); }
});
});
The default onfocusout looks like this, disabling the blur validation until after it's been submitted once:
onfocusout: function(element) {
if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
this.element(element);
}
}