โ๏ธ Check out my blog at SimonReynolds.ie
๐จ he/him/sรฉ/รฉ
๐ Dublin, Ireland
Home Page: https://simon-reynolds.github.io/jquery.dirty/
License: MIT License
โ๏ธ Check out my blog at SimonReynolds.ie
๐จ he/him/sรฉ/รฉ
๐ Dublin, Ireland
I have a form that contains a select box, after adding the dirty to the form, the events on the select box stopped working.
I used some https://github.com/radiac/django-tagulous fields in my https://github.com/jedie/PyInventory project and whant to use https://github.com/simon-reynolds/jquery.dirty to warn user about unchanged forms.
Sadly jquery.dirty doesn't handle django-tagulous fields correctly. It raised the unchaned warning for new, but not filled forms and raise no warning on changes :(
tagulous used https://github.com/select2/ and the code looks like this:
Any idea how to fix this?
(Crosspost: radiac/django-tagulous#156 )
Hi,
I'm using select2.js and Ajax for chained drop down
Country, State, City
If the field are empty on page load then if I select items, then clear all 3 fields I'm getting the form dirty...
This seems related to when the code call .empty();
I saw that you have a refreshEvents is this something that could use for this problem?
Thanks
Is jquery.dirty will work with input type file?
I'm using jquery.filer.js
the <input type="file" name="files[]">
once I have upload a file and remove the file it still getting data-is-dirrty="true"
Here is a demo of jquery.filer as the project is no longer available on Github... https://www.tutorialspoint.com/jquery/src/filer/index.htm
Thanks
Using npm i jquery.dirty
brings up an error:
> [email protected] preinstall [snip]\node_modules\jquery.dirty
> npx npm-force-resolutions
npx: installed 5 in 1.727s
ENOENT: no such file or directory, open './package-lock.json'
It seems to be caused by b54f03b adding
"preinstall": "npx npm-force-resolutions",
Installing 0.7.2 works fine.
References:
oktadev/schematics#192 (comment)
I'm having 2 differents forms on tabs (bootstrap tabs)
tab1 = form1
tab2 = form2
Let say a user made a change on tab1 form and click on a tab2, I want to detect this even as a quit before saving.
What will be the best way to do it?
Question: Do you have support to show the "leave popup" manually for bootstrap tabs?
/*
(function ($) {
//Save dirty instances
var singleDs = [];
var dirty = "dirty";
var clean = "clean";
var dataInitialValue = "dirtyInitialValue";
var dataIsDirty = "isDirty";
var formIsDirty = false;
var $el;
var thisIsDirty;
var result;
var $this;
var $e;
var initialValue;
var currentValue;
var getSingleton = function (id) {
singleDs.forEach(function (e) {
if (e.id === id) {
result = e;
}
});
return result;
};
var setSubmitEvents = function (d) {
d.form.on("submit", function () {
d.submitting = true;
});
if (d.options.preventLeaving) {
$(window).on("beforeunload", function (event) {
if (d.isDirty && !d.submitting) {
event.preventDefault();
return d.options.leavingMessage;
}
});
}
};
var setNamespacedEvents = function (d) {
d.form.find("input, select, textarea").on("change.dirty click.dirty keyup.dirty keydown.dirty blur.dirty", function (e) {
d.checkValues(e);
});
d.form.on("dirty", function () {
d.options.onDirty();
});
d.form.on("clean", function () {
d.options.onClean();
});
};
var clearNamespacedEvents = function (d) {
d.form.find("input, select, textarea").off("change.dirty click.dirty keyup.dirty keydown.dirty blur.dirty");
d.form.off("dirty");
d.form.off("clean");
};
var Dirty = function (form, options) {
this.form = form;
this.isDirty = false;
this.options = options;
this.history = [clean, clean]; //Keep track of last statuses
this.id = $(form).attr("id");
singleDs.push(this);
};
Dirty.prototype = {
init: function () {
this.saveInitialValues();
this.setEvents();
},
isRadioOrCheckbox: function (el) {
return $(el).is(":radio, :checkbox");
},
isFileInput: function (el) {
return $(el).is(":file")
},
saveInitialValues: function () {
$this = this;
this.form.find("input, select, textarea").each(function (_, e) {
if ($this.isRadioOrCheckbox(e)) {
$(e).data(dataInitialValue, ($(e).is(":checked") ? "checked" : "unchecked"));
} else if ($this.isFileInput(e)) {
$(e).data(dataInitialValue, JSON.stringify(e.files))
} else {
$(e).data(dataInitialValue, $(e).val() || '');
}
});
},
refreshEvents: function () {
clearNamespacedEvents(this);
setNamespacedEvents(this);
},
showDirtyFields: function () {
return this.form.find("input, select, textarea").filter(function (_, e) {
return $(e).data("isDirty");
});
},
setEvents: function () {
setSubmitEvents(this);
setNamespacedEvents(this);
},
isFieldDirty: function ($field) {
initialValue = $field.data(dataInitialValue);
// Explicitly check for null/undefined here as value may be `false`, so ($field.data(dataInitialValue) || '') would not work
if (initialValue == null) { initialValue = ''; }
currentValue = $field.val();
if (currentValue == null) { currentValue = ''; }
// Boolean values can be encoded as "true/false" or "True/False" depending on underlying frameworks so we need a case insensitive comparison
if ((/^(true|false)$/i).test(initialValue) && (/^(true|false)$/i).test(currentValue)) {
return !(new RegExp("^" + initialValue + "$", "i")).test(currentValue);
}
return currentValue !== initialValue;
},
isFileInputDirty: function ($field) {
return JSON.stringify(($field[0]).files) !== $field.data(dataInitialValue);
},
isCheckboxDirty: function ($field) {
return $field.data(dataInitialValue) !== $field.is(":checked") ? "checked" : "unchecked";
},
checkValues: function (e) {
$this = this;
formIsDirty = false;
this.form.find("input, select, textarea").each(function (_, el) {
$el = $(el);
if ($this.isRadioOrCheckbox(el)) {
thisIsDirty = $this.isCheckboxDirty($el);
} else if ($this.isFileInput(el)) {
thisIsDirty = $this.isFileInputDirty($el);
} else {
thisIsDirty = $this.isFieldDirty($el);
}
$el.data(dataIsDirty, thisIsDirty);
formIsDirty |= thisIsDirty;
});
if (formIsDirty) {
$this.setDirty();
} else {
$this.setClean();
}
},
setDirty: function () {
this.isDirty = true;
this.history[0] = this.history[1];
this.history[1] = dirty;
if (this.options.fireEventsOnEachChange || this.wasJustClean()) {
this.form.trigger("dirty");
}
},
setClean: function () {
this.isDirty = false;
this.history[0] = this.history[1];
this.history[1] = clean;
if (this.options.fireEventsOnEachChange || this.wasJustDirty()) {
this.form.trigger("clean");
}
},
//Lets me know if the previous status of the form was dirty
wasJustDirty: function () {
return (this.history[0] === dirty);
},
//Lets me know if the previous status of the form was clean
wasJustClean: function () {
return (this.history[0] === clean);
},
setAsClean: function () {
this.saveInitialValues();
this.setClean();
},
setAsDirty: function () {
this.saveInitialValues();
this.setDirty();
},
resetForm: function () {
$this = this;
this.form.find("input, select, textarea").each(function (_, e) {
$e = $(e);
if ($this.isRadioOrCheckbox(e)) {
$e.prop("checked", ($e.data(dataInitialValue) === "checked"));
} if ($this.isFileInput(e)) {
e.value = "";
$(e).data(dataInitialValue, JSON.stringify(e.files))
} else {
$e.val($e.data(dataInitialValue));
}
});
this.checkValues();
}
};
$.fn.dirty = function (options) {
if (typeof options === "string" && /^(isDirty|isClean|refreshEvents|resetForm|setAsClean|setAsDirty|showDirtyFields)$/i.test(options)) {
//Check if we have an instance of dirty for this form
// TODO: check if this is DOM or jQuery object
$this = getSingleton($(this).attr("id"));
if (!$this) {
$this = new Dirty($(this), options);
$this.init();
}
switch (options.toLowerCase()) {
case "isclean":
return !$this.isDirty;
case "isdirty":
return $this.isDirty;
case "refreshevents":
$this.refreshEvents();
case "resetform":
$this.resetForm();
case "setasclean":
return $this.setAsClean();
case "setasdirty":
return $this.setAsDirty();
case "showdirtyfields":
return $this.showDirtyFields();
}
} else if (typeof options === "object" || !options) {
return this.each(function (_, e) {
options = $.extend({}, $.fn.dirty.defaults, options);
(new Dirty($(e), options)).init();
});
}
};
$.fn.dirty.defaults = {
preventLeaving: false,
leavingMessage: "There are unsaved changes on this page which will be discarded if you continue.",
onDirty: $.noop, //This function is fired when the form gets dirty
onClean: $.noop, //This funciton is fired when the form gets clean again
fireEventsOnEachChange: false, // Fire onDirty/onClean on each modification of the form
};
})(jQuery);
I was wondering why setAsClean isn't triggering the onClean callback, if there is no reason, I'd like to create a PR and add it, just wanted to know before working on it.
*Same thing for resetForm
Hi, first of all, thank you very much for the handy plugin. It is really useful and I found it from a stack overflow answer.
My form has a rich text editor fields (CK Editors). Your plugin can detect the dirtiness of all other fields but those rich text editors. Is there any attributes to be set to make it work with rich text editors or it just isn't implemented? If it an unimplemented feature, is there a work around?
Thanks!
Hi,
I'm using an hybrid version a mix of yours and the original dirrty script.
I'm using this datepicker https://github.com/uxsolutions/bootstrap-datepicker
If I enable the datepicker clear button clearBtn: true,
this is not triggering a change when I clear the value and not enabling the save button
Any clue how I could handle this case?
Hello,
is jquery.dirty supposed to work on iOS Safari? In my tests, it doesn't work (the warning never appears).
The beforeunload event should work on iOS, though.
Thanks
E.
Let say I have two forms on the same page with different ids for the form and the submit
I edited both forms so they have both dirtty fields
If I click one of the submit button I will get beforeunload notification.
Any way to fix that?
Note:
I have redo my page and now it's working fine I'll close this for now as I don't know how to reproduce.
This works properly, but the leavingMessage is ignored.
On Firefox it shows the default, on Chrome "Leave Site? The changes you made may not be saved"
Let say the form data are sent and saved in DB.
How can I set the form back to clean without reloading the page?
Thanks
Do you have an example of how to stop the message appearing when you click a save/submit button?
Hi,
I'm setting the form as dirty on page load $("#add").dirty("setAsDirty");
and if I quit the page it's not alerting and the button stay disable
How should I use it?
If called via:
$('form').dirty();
For forms with no ID set, then a lot of features do not work. Can the array of forms not be identified using something other than ID?
For example:
dirty("resetForm")
No longer works
Hello,
I have noticed that the form gets "dirty" even if I just click into a textbox without changing anything.
Is this the intended behaviour? Is it possible to change the status to "dirty" only if the form has actually been changed?
Thanks.
Best,
At the moment onDirty
is only fired when the form is first dirtied
We may want to fire it each time the form is modified
e.g. if a user enters text that is longer than the form allows, then we may want to disable the save button
I was experiencing strange behavior with resetForm
being called unexpectedly and realized the switch statement doesn't break or return here:
case "refreshevents":
d.refreshEvents();
case "resetform":
d.resetForm();
So when you call refreshEvents
it will also call resetForm
.
Additionally there is a similar issue in resetForm, which was causing my checkbox values to be set to value="unchecked"
and value="checked"
:
if (isRadioOrCheckbox) {
var initialCheckedState = $e.data(dataInitialValue);
var isChecked = initialCheckedState === "checked";
$e.prop("checked", isChecked);
} if(isFile) {
e.value = "";
$(e).data(dataInitialValue, JSON.stringify(e.files))
} else {
var value = $e.data(dataInitialValue);
$e.val(value);
}
The second if
should be an else if
, which explains why my checkbox values were being changed.
I am putting together a pull request with these changes.
Hi,
If you find the time, could you set up a demo page, with some basic instructions.
Thanks
Hi,
I have a case that a form is pre-filled with some data, so I need to set the form to dirty on page load.
Do I need to create a setAsDirty or is there a way to call an existing function to do it setDirty?
Any help or guidance is welcome
Thanks
Hello,
I have an issue caused by the stopImmediatePropagation
at the end of checkValues
.
This prevent other subscribers to react to key press on form. In my example, jquery validation do not validate input field after key has been pressed.
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
jquery
, @types/jquery
).github/workflows/codeql-analysis.yml
actions/checkout v3
github/codeql-action v2
github/codeql-action v2
github/codeql-action v2
.github/workflows/npm-publish.yml
actions/checkout v3
actions/setup-node v3
actions/checkout v3
actions/setup-node v3
actions/checkout v3
actions/setup-node v3
package.json
@types/jquery 3.5.14
braces 3.0.2
jquery 3.6.0
kind-of 6.0.3
minimist 1.2.6
node-qunit-phantomjs 2.1.1
qunitjs 2.4.0
minimist 1.2.6
braces 3.0.2
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.