I am using Quill (Rich Text) and need to find a way to checking to see if the text has changed when the page does a form submit. I am quite new to using Quill and have been looking at the events here. Using the text-change triggers everytime the text is changed (obviously) but I have other Form Input controls on the page which are checked on form submit to see if they have changed... I need my RTF boxes to do the same.
EDIT
I have managed to get the Event Firing using the example below. My problem now is that the event appears to trigger even when the editor is pre-populated on page load. I dont want to acknowledge these initial loads, only if the text has been changed by a user.
Two ways to do so:
1) listen for quill changes and if any occurred, raise a flag telling your form content has changed (flow: if you add a char, then delete it, your flag would be true even if resulting content is the same)
Using :
let changes = false
quill.on('text-change', function(delta, oldDelta, source) {
changes = true
})
2) comparing two snapshots of the document to detect front-end if changes occurred. You could either compare strings (with quill.getText()) this is the simplest, but you could miss lot of things, I would recommend to compare objects (with quill.getContents()) and use lodash or other deep equality objects method check.
Using:
const initialContents = quill.getContents()
const beforeSubmitContents = quill.getContents()
const hasChanged = _.isEqual(initialContents.ops, beforeSubmitContents.ops)
for detect if exis change only implement this function
quill.on('text-change', function(delta, oldDelta, source) {
if (source == 'api') {
console.log("An API call triggered this change.");
} else if (source == 'user') {
console.log("A user action triggered this change.");
}
});
this function detect if write or have a change on editor, detect if has change on your words or font or image...etc.. !!
In this case i use the example of official page:
page official
result :
Related
Often, in different websites, when I input text into a field with JavaScript (for the sake of automating form filling):
document.querySelector("#username").value = "USERNAME";
I encounter the following problem.
My problem
The above very inputting of text via JavaScript, either manually by devtool console or by a userscript manager, isn't effective so the form could not be submitted and I am asked something like "fill in data in all fields".
A way to deal with that is to delete the last (or first) character of the inputted text and then re-input that character manually myself and then the ext will be recognized but it's not really a solution.
A failed solution
I have tried to cope with the aforementioned problem with the following pattern, which failed:
1) Manually mouselick on all fields and then execute in devtool console:
dispatchEvent(new Event("keydown"));
dispatchEvent(new Event("keyup"));
dispatchEvent(new Event("change"));
true
2) Manually mouselick on all fields again;
My question
What can make a web application not recognizing the very inputting of values with JavaScript?
What can prevent the data being recognized unless at least one characters of it is manually changed?
Some possibilities of how a page may not recognize a programmatically inputted value are:
It may be listening for a different event from the one you're triggering. There are many types of events related to inputting text, including keypress, input, and focus. Take a look at what's logged in the following snippet when you manually click on the input and press keys:
let obj = input;
while (obj) {
for (const prop of Object.getOwnPropertyNames(obj)) {
if (!prop.startsWith('on')) continue;
input.addEventListener(prop.slice(2), () => console.log(prop.slice(2)));
}
obj = Object.getPrototypeOf(obj);
}
<input id="input">
The script may require one of those initial events to be fired before it starts processing other events. For example, perhaps the script requires a focus event before it starts observing key changes in the input. (Similarly, the script may be listening for events in a particular order, though that'd be pretty odd)
The script may also check if the event is trusted or not. Only user-initiated events are trusted; events dispatched via Javascript are not:
input.addEventListener('input', (e) => {
console.log(e.isTrusted);
});
setTimeout(() => {
input.dispatchEvent(new Event('input'));
}, 1000);
<input id="input">
In a situation like the above, your options to bypass it include
Triggering the event using something outside a browser, such as with AutoHotKey
Intercepting the <script> that adds the functionality and tweaking it so that it doesn't check if the event is trusted. Here's an example of doing that on Stack Exchange.
I need to update single item of object in localstorage without reloading page.
jsFiddle: https://jsfiddle.net/7xsg8679/
Here is my code:
if (obj.isCompletedTask === false) {
newDone.innerHTML = "Not done";
newDone.dataset.done = false;
newButton.addEventListener('click', function (e) {
newDone.innerHTML = "Done";
newDone.dataset.done = true;
newUl.style.backgroundColor = "red";
e.preventDefault();
})
}
If I use if(obj.isCompletedTask === true) in the if-statement - it does nothing. Why?
When you use obj.isCompletedTask === true the button does nothing isCompletedTask is false, so the code between curly brackets { ... } is not run at all, so the eventListener does not get attached to your button click event.
You may want to move your if statement to inside of event listener, if i understood your intentions correctly.
When you want to update an element in localstorage, you do it like that:
localStorage.setItem('list', JSON.stringify(tasks));
...but when your tasks object changes, you need to keep a track of that yourself, and manually update localStorage. This relation is called data-binding. Moreover, you cannot just update subelement of your tasks directly, you have to replace list in localStorage with fresh version of tasks every time something in tasks changes.`
General remark: from what i see in your fiddle, i do really think you should have a look at some framework (like vue, react or angular). Keeping track of the changes here and there will really be tiresome after a while and besides, why should yo reinvent the wheel?
I've written a script for my registration form that if there's a keyup event on the username input field, then javascript checks if the username entered is valid and if it's then an ajax function is called to check its availability.
It's working fine. But username can be entered without doing a key up, what to do for those cases? E.g. username can be entered by clicking the input field and selecting a name suggested by the browser, Or by using an auto-form filler. There's no "keyup" in these cases, so what to do for these cases?
And if I am missing some case then pls tell.
Bind the callback to the change event too.
Instead of $('username_input').keyup or $('username_input').bind('keyup', callback) use
$('username_input').bind('keyup change blur', function () {
//
})
[UPDATE]
If you are not using jQuery try
function checkUserName() {
// Ajax validation code
}
userinput = document.getElementById('yourusernameinputid');
userinput.onclick = userinput.onchange = userinput.onblur = checkUserName;
on a side note, you should try learning jQuery. It could save you a lot of time, and help you make better sites in less time.
[UPDATE 2]
It looks like there is no way to detect change via autofill using events. You need to set a timer to automatically check your input at fixed interval and check with you last value.
(function() {
// It is always better to use a closure to prevent the value from
// getting overwritten by another piece of code
var value = '';
setInterval(2000, function() {
if (userinput.value != value) {
checkUserName();
value = userinput.value;
}
});
})();
Test the username when:
The blur event occurs (when the text field loses its focus), and
Before the user sumits the form, or
The change event occurs (I think this is the best).
setInterval is the only way.
Sources:
I want to trigger an event every single time data changes in an HTML text input field regardless of focus
jQuery: What listener do I use to check for browser auto filling the password input field?
SendKeys is method to sending keystroke to an application.
Can I do it in Javascript, to send keystroke in browser ?
REF :
http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.aspx
If you would be able to send keystrokes on the OS Level, this would be a big security issue.
You could (for instance) install any kind of software on the client machine if you where able to send keystrokes to the needed install dialogs.
Yes, you could come up with an active-x control or some other tools to be installed on the client machine. But because of the security issues with such a tool, I wouldn't do it -- even in a controlled environment.
Most of the time, there is a way to achieve your needed functionality without breaching the security.
Update: If you want to jump to the next tabfield, you have to use the focus() method to set the focus to the next element. Unfortunately, you have to find the next element by yourself in javascript, but this should not be a big problem - you can keep an ordered list of all your elements in javascript.
btw: http://forums.devarticles.com/javascript-development-22/moving-to-next-tabindex-on-event-2382.html
There are lots of JS Framework implemented event simulation inside web page.
Is it possible to simulate key press events programmatically? for jQuery
Javascript: simulate a click on a link for YUI
However, simpler method is that the third post of the link given by Ralf which focus the "next" textfield regarding to the tabIndex property of elements inside a form element.
There might be a more brilliant way if you make up a list of textfield's IDs and the order you want to be.
Of course, the tabIndex list might not be generated by yourself but by walking around the textfield.
Create a loop to generate the list when document is loaded (DOMContentLoaded):
var tabIndexList = new Array();
function tabIndexListGeneration(){
var form = document.getElementById("Your form ID"), // remember to fill in your form ID
textfields = form.getElementsByTagName("input"),
textfieldsLength = textfields.length;
for(var i=0;i<textfieldsLength;i++){
if(textfields[i].getAttribute("type") !== "text" || textfields[i].getAttribute("tabIndex") <= 0)continue;
/* tabIndex = 0 is neglected as it places the latest, if you want it, change 0 to -1
* and change tabIndexPointer = 0 into tabIndexPointer = -1 below */
tabIndexList[textfields[i].getAttribute("tabIndex")] = textfields[i];
}
}
// You can use the function of JS Framework if you don't like the method below.
if(document.addEventListener){
document.addEventListener("DOMContentLoaded", tabIndexListGeneration, false);
}else{
window.attachEvent("onload", tabIndexListGeneration);
}
And inside the event of "text input equals textfield maxlength":
var tabIndexPointer = target.getAttribute("tabIndex"); // target is the DOM object of current textfield
while(!(++tabIndexPointer in tabIndexList)){
if(tabIndexPointer >= tabIndexList.length)
tabIndexPointer = 0; // or other action after all textfields were focused
}
tabIndexList[tabIndexPointer].focus(); // if other action needed, put it right after while ended
Note: form textfields' structure must not be mutated otherwise an error would be given out.
If textfield generate dynamically, run tabIndexListGeneration() to regenerate the list.
This works for me. The ActiveXObject needs to be opened in IE.
var PaintProg = new ActiveXObject("WScript.Shell"); //paste to mspaint
PaintProg.Run("mspaint.exe \\\\srv4\\photos\\image1.jpg",9,false);
var PaintTimer = window.setInterval(PaintPaste,1000);
function PaintPaste()
{
if (PaintProg.AppActivate("Paint",true) == true)
{
PaintProg.SendKeys('"^(v)""%(F)""x""~"',true);
window.clearInterval(PaintTimer);
}
}
Not by default in most browsers, no. You may be able to get it to work using ActiveX if it's going to be running in Internet Explorer, however.
I have configured the dojo combobox as follows:
this.autoComplete = new dijit.form.ComboBox( {
id : this.name + "_term",
name : "search_id",
store : this.dataStore,
searchAttr : "term",
pageSize : "30",
searchDelay:500,
value : this.config.inputText,
hasDownArrow : false
}, this.name + "_term");
The issue here is that when the user enters their search term and hits [Enter] before the 500ms, the service request gets canceled (common when copy and pasting a search term). What I expected to happen is for it to simply ignore the [Enter] event until the request is complete and options are displayed in the dropdown. The user could then hit enter again to submit the first item in the response.
Hoping to get some suggestions on how to handle this scenario. I've looked through the api for dijit.form.ComboBox, but didn't see anything compelling that could address this. Note that the exact same behavior exists if I use FilteringSelect instead of ComboBox. The interesting thing is that FilteringSelect treats this scenario as an error that is handled by the "invalidMessage" param. I don't understand the benefit of treating this as an error.
I've (temporarily) solved the issue by monkey patching dijit.form.ComboBox by overriding the _onKeyPress function. I'm using dojo v1.5 and noticed that v1.6 changed _onKeyPress to _onKey. So upgrading will obviously break things.
I've updated the [Enter] event handling like so:
case dk.ENTER:
// prevent submitting form if user presses enter. Also
// prevent accepting the value if either Next or Previous
// are selected
if(highlighted){
// only stop event on prev/next
if(highlighted == pw.nextButton){
this._nextSearch(1);
dojo.stopEvent(evt);
break;
}else if(highlighted == pw.previousButton){
this._nextSearch(-1);
dojo.stopEvent(evt);
break;
}
}else{
if (!module.autoComplete.item) {
doSearch = true;
}
// Update 'value' (ex: KY) according to currently displayed text
this._setBlurValue(); // set value if needed
this._setCaretPos(this.focusNode, this.focusNode.value.length); // move cursor to end and cancel highlighting
}
// default case:
// prevent submit, but allow event to bubble
evt.preventDefault();
// fall through
break;
The code in question is:
if (!module.autoComplete.item) {
doSearch = true;
}
I'm basically telling it to do the search only if the autocomplete object instance exists and hasn't recieved any items yet. This is an ugly hack, but it's solving the issue for the moment. I would still love some suggestions on how to handle this better.