django-jet
django-jet copied to clipboard
Jquery on Change not working on ChoiceField
Hi there,
I'm trying to attach specific display on the values of a select drop-down (multiple choice field) but it's not working. I see that it's not the select itself that is displayed but an added with the following id : select2-id_ptype-container. Using jquery .change() on the select, nothing happens (as if due to the overwrite of the display, the change on the select isn't fired)
How should I approach this?
ptype = models.IntegerField(choices=TYPE_CHOICES, verbose_name="Type de la personne")
Select généré
<select id="id_ptype" name="ptype" required>
span ajouté
<span class="select2 select2-container select2-container--jet select2-container--below" dir="ltr" style="width: auto;">
<span class="selection">
<span class="select2-selection select2-selection--single" role="combobox" aria-autocomplete="list" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-labelledby="select2-id_ptype-container">
<span class="select2-selection__rendered" id="select2-id_ptype-container" title="Type1">Type1</span><span class="select2-selection__arrow" role="presentation"><b role="presentation"></b>
</span>
</span>
</span>
I'm having the same problem.
I think it happens because the <select> used by the user is dinamically created, so jQuery can't access it directly.
In theory you could bind the element with ".on()" on the container that the element was dinamically added (this container needs to be on the page when you load it), but it also don't worked for me too... Anyway, the code is something like:
$("#FixedContainer").on("click", "#DinamicElement", function(){ // bla bla bla... });
In theory it should work. But? The change event does not fire. And calling the select2 plugin does not work.
$el.select2();
//select2 is not a function. (In 'el.select2()', 'el.select2' is undefined)
I got very close using DOMSubtreeModified, like this:
$el.on('DOMSubtreeModified', function () {
alert ( $(this).text() );
});
But there are many events (bubbles) ...
I do not really know how to get this value when the select changes, if you can, please let me know.
Thank you!
@f1nality Here there is other problem with jquery
.
I've got the same issue here, the change event does not fire. Are we listening on the wrong object?
I have the same problem when trying to embebed a Google Maps map inside a dashboard module that displays routes, the route displayed changes according to the place selected, but in django-jet the event is never fired, opening the template in a stand alone tab in chrome, works fine. There are also selection issues in FireFox. I see there are a lot of issues with Select-2 @f1nality is there an alternative to this library?
In latest dev, if I click the select option it doesn't even pick it up, the options pop up just stays there:
@Ismael-VC can you provide a traceback from debug console in browser or from console in python? Thanks!
@SalahAdDin sure thing, this is the working map, just opening the template in a new tab:
Here is the Maps dashboard module template:
{% load humanize %}
<div style="text-align: center;">
<b>Start: </b>
<select id="route_start">
<option value="Ciudad de Queretaro">Queretaro</option>
<option value="Ciudad de Hermosillo">Hermosillo</option>
</select>
<b>End: </b>
<select id="route_end">
<option value="Ciudad de México">México</option>
<option value="Ciudad de Sonora">Sonora</option>
</select>
</div>
<div id="route_map" style="width: 100%; height: 350px;"></div>
<script>
function initMap() {
// ROUTE MAP
var routeMapCanvas = document.getElementById("route_map");
var routeMapOptions = {
center: new google.maps.LatLng(19.3910036, -99.2840421),
zoom: 7,
panControl: true,
zoomControl: true,
mapTypeControl: true,
scaleControl: true,
streetViewControl: true,
overviewMapControl: true,
rotateControl: true
};
var route_map = new google.maps.Map(routeMapCanvas, routeMapOptions);
var directionsService = new google.maps.DirectionsService;
var directionsDisplay = new google.maps.DirectionsRenderer;
directionsDisplay.setMap(route_map);
function onChangeHandler() {
calculateAndDisplayRoute(directionsService, directionsDisplay);
};
// Event listeners to select elements:
document.getElementById("route_start").addEventListener('click', onChangeHandler);
document.getElementById('route_end').addEventListener('change', onChangeHandler)
}
function calculateAndDisplayRoute(directionsService, directionsDisplay) {
directionsService.route({
origin: document.getElementById('route_start').value,
destination: document.getElementById('route_end').value,
travelMode: google.maps.TravelMode.DRIVING
}, function (response, status) {
if (status === google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
} else {
window.alert('Directions request failed due to ' + status);
}
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"></script>
Here is the error when I try to select an option:
This is the traceback:
2017-04-09 11:56:53.030 bundle.min.js?v=1.0.5:1 Uncaught TypeError: django.jQuery is not a function
at HTMLSelectElement.<anonymous> (bundle.min.js?v=1.0.5:1)
at HTMLSelectElement.dispatch (bundle.min.js?v=1.0.5:9)
at HTMLSelectElement.m.handle (bundle.min.js?v=1.0.5:9)
at Object.trigger (bundle.min.js?v=1.0.5:9)
at HTMLSelectElement.<anonymous> (bundle.min.js?v=1.0.5:9)
at Function.each (bundle.min.js?v=1.0.5:8)
at ot.fn.init.each (bundle.min.js?v=1.0.5:7)
at ot.fn.init.trigger (bundle.min.js?v=1.0.5:9)
at n.select (bundle.min.js?v=1.0.5:12)
at o.<anonymous> (bundle.min.js?v=1.0.5:12)
(anonymous) @ bundle.min.js?v=1.0.5:1
dispatch @ bundle.min.js?v=1.0.5:9
m.handle @ bundle.min.js?v=1.0.5:9
trigger @ bundle.min.js?v=1.0.5:9
(anonymous) @ bundle.min.js?v=1.0.5:9
each @ bundle.min.js?v=1.0.5:8
each @ bundle.min.js?v=1.0.5:7
trigger @ bundle.min.js?v=1.0.5:9
n.select @ bundle.min.js?v=1.0.5:12
(anonymous) @ bundle.min.js?v=1.0.5:12
n.invoke @ bundle.min.js?v=1.0.5:11
n.trigger @ bundle.min.js?v=1.0.5:11
o.trigger @ bundle.min.js?v=1.0.5:13
(anonymous) @ bundle.min.js?v=1.0.5:13
n.invoke @ bundle.min.js?v=1.0.5:11
n.trigger @ bundle.min.js?v=1.0.5:11
(anonymous) @ bundle.min.js?v=1.0.5:11
dispatch @ bundle.min.js?v=1.0.5:9
m.handle @ bundle.min.js?v=1.0.5:9
At first I thought it was related to django-autocomplete-light
:
INSTALLED_APPS = [
# django-autocomplete-light
# 'dal',
# 'dal_select2',
# Jet Bootstrap
'jet.dashboard',
'jet',
# ...
]
But this is the error shown: TypeError: django.jQuery is not a function
and this still happens when I disable dal
and dal_select2
.
@f1nality here is the code from bundle.min.js
at the initSelect
function:
initSelect: function(t, e) {
var i = {
theme: "jet",
dropdownAdapter: e,
width: "auto"
};
if (t.hasClass("ajax")) {
var n = t.data("content-type-id")
, o = t.data("app-label")
, s = t.data("model")
, r = t.data("object-id")
, a = 100;
i.ajax = {
dataType: "json",
data: function(t) {
return {
content_type: n,
app_label: o,
model: s,
q: t.term,
page: t.page,
page_size: a,
object_id: r
}
},
processResults: function(t, e) {
if (t.error)
return {};
e.page = e.page || 1;
var i = e.page * a < t.total;
return {
results: t.items,
pagination: {
more: i
}
}
}
}
}
t.on("change", function(e) {
django.jQuery(t.get(0)).trigger(e) // Here the exception is thrown.
}),
t.select2(i)
},
So this means Select2 is never initialized.
The file in question is: static\jet\build\bundle.min.js
I have tried manually editing this generated file like this:
t.on("change", function(e) {
var $ = jQuery.noConflict(true);
$(t.get(0)).trigger(e)
})
But I'm still learning JS and I think this file is cached somewhere, because I don't see the cange being reflected, I'll keep trying to make it work.
@Ismael-VC Is these bundle yours or comes from django-jet
project?
@SalahAdDin It's part of django-jet dev.
@SalahAdDin @f1nality I have figured out that part of the file static\jet\build\bundle.min.js
is built from jet/static/jet/js/src/features/selects.js
Combined JS scripts of JET – jet/static/jet/js/build/bundle.min.js
I should have red CONTRIBUTING
sooner, this is the commit that introduced the line with django.jQuery
, it's there to fix some previous problem (maybe intended to close this issue?):
- https://github.com/geex-arts/django-jet/commit/a0d8b503af92eac9a3d1970b70212872f6b23149
The problem with Uncaught TypeError: django.jQuery is not a function
only happens in the /admin page, other views are not affected AFAICT:
Maybe the problem is a merge ordering of the scripts.
@SalahAdDin could you please update and try to reproduce this error please? @f1nality has just merged dev back into master a few hours ago:
- https://github.com/geex-arts/django-jet/commit/45e94712b35409652bf984bcadcdbc923c2ec2ae#diff-00db1b427cdf9ae5b3b45e603ae3225a
Ok, i'll install it from master.
django.jQuery
is used only at:
-
jet/static/jet/js/src/features/selects.js
-
jet/templates/rangefilter/date_filter.html
According to git grep "django.jQuery"
, but I can't see where it is defined anywhere. django.jQuery
is undefined in /admin
:
However it is defined in the other pages, here /admin/catalogs_app/unit/
, where catalogs_app
is my main app, but it also works in other apps:
If I double click the output of django.jQuery
in the chrome console, it opens the file in the line where jQuery
is defined, in jquery.js
itself.
Ok, I'm beginning to get the hang out of this, I have done the following:
- Fork django-jet
- Install node and gulp
- Run
node install
in the django-jet dir, to install all dependencies - Run
gulp
to listen for any changes in the static files and to rebuild automatically:static\jet\build\bundle.min.js
- I've edited `jet/static/jet/js/src/features/selects.js``
diff --git a/jet/static/jet/js/src/features/selects.js b/jet/static/jet/js/src/features/selects.js
index 7f99f6f..47d5227 100644
--- a/jet/static/jet/js/src/features/selects.js
+++ b/jet/static/jet/js/src/features/selects.js
@@ -190,7 +190,7 @@ Select2.prototype = {
}
$select.on('change', function(e) {
- django.jQuery($select.get(0)).trigger(e);
+ $($select.get(0)).trigger(e);
});
$select.select2(settings);
But this causes: Uncaught RangeError: Maximum call stack size exceeded
I don't really understand why.
This is the whole backtrace for that error:
- https://gist.github.com/Ismael-VC/136997eac77eab0bb88d3ceaac79a09f
Ok I've also tried changing to:
diff --git a/jet/static/jet/js/src/features/selects.js b/jet/static/jet/js/src/features/selects.js
index 7f99f6f..5c8095a 100644
--- a/jet/static/jet/js/src/features/selects.js
+++ b/jet/static/jet/js/src/features/selects.js
@@ -190,6 +190,8 @@ Select2.prototype = {
}
$select.on('change', function(e) {
+ var django = django || {};
+ django.jQuery = jQuery.noConflict(true);
django.jQuery($select.get(0)).trigger(e);
});
But now the Chrome console, tells me that Uncaught TypeError: Cannot read property 'noConflict' of undefined
, so django
is also undefined in /admin
. :(
I found django.jQuery
is defined at:
- https://github.com/django/django/blob/master/django/contrib/admin/static/admin/js/jquery.init.js
Here is a comment and issue that seems relevant:
- https://github.com/django/django/pull/6900#issuecomment-232067080
- https://code.djangoproject.com/ticket/26885
Sorry, I make a mistake. I found the real jquery.init.js file comes from django-autocomplete-light package. this project rewrite jquery.init.js file.
I did had django-autocomplete-light
installed at some point, but I uninstalled it, deleted static
in my project and re ran collectstatic
, however, since I clearly don't know JS-fu, I'll start from scratch and see if it happens.
@SalahAdDin were you able to reproduce this error? If you can't then that means it's only on my side, and that would make me think it really had something to do with django-autocomplete-light
.
@f1nality I can reproduce this in a completely new environment, a new project and using current django-jet master.
Steps to reproduce:
- Create a new virtual environment (I'm using conda):
-
conda create -n foo python==3.6 django==1.10.6
-
- Activate virtual environment:
-
activate foo
-
- Start project:
-
django-admin startproject Foo && cd Foo
-
- Install django-jet from master:
-
pip install git+https://github.com/geex-arts/django-jet@master
-
- Make initial migrations:
-
python manage.py migrate
-
- Create superuser:
-
python manage.py createsuperuser
-
- Configure static files, by adding the following to
settings.py
:
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATICFILES_FINDERS = [
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
]
- Configure urls:
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^jet/', include('jet.urls', 'jet')),
url(r'^jet/dashboard/', include('jet.dashboard.urls', 'jet-dashboard')),
url(r'^admin/', admin.site.urls),
]
- Run django-jet initial migrations:
-
python manage.py migrate
-
- Run collect static:
-
python manage.py collectstatic
-
- Start server:
-
python manage.py runserver
-
- Go to Chrome and open
http://127.0.0.1:8000/admin/
- Open the Chrome development tools (F12)
- Try to select an option from the widgets dropdown.
- At the end you should see in the Chrome JS console, the following error:
-
Uncaught TypeError: django.jQuery is not a function
-
Am I doing something wrong?
@SalahAdDin @f1nality where you able to reproduce this?
Hi, I'm having this issue, all selects in django-admin return on Uncaught TypeError: django.jQuery is not a function, there is some workaround that can be apply?
Add to folder : jet/static/jet/js/build/ file jquery.init.js with a code:
/*global django:true, jQuery:false*/
/* Puts the included jQuery into our own namespace using noConflict and passing
* it 'true'. This ensures that the included jQuery doesn't pollute the global
* namespace (i.e. this preserves pre-existing values for both window.$ and
* window.jQuery).
*/
var django = django || {};
django.jQuery = jQuery.noConflict(true);
next in file: jet/templates/admin/base.html add 2 lines in the head:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script src="{% static "jet/js/build/jquery.init.js" as url %}{{ url|jet_append_version }}"></script>
It should solve your problem. Success!
@f1nality what's about @arbak solution?
It will fix : Jquery on Change not working on ChoiceField and django.jQuery is not a function error
@arbak and what about "RangeError: Maximum call stack size exceeded." in all selects in Django-admin? I'm still getting this with Django-jet at master. Any solution?
@f1nality Please.
nothing yet about a solution?
ref #230 why trigger on recursive ?
https://github.com/geex-arts/django-jet/blob/dev/jet/static/jet/js/src/features/selects.js#L193
:+1:
Bump? This will end up making me have to remove jet :/
@rbp Im pissed off too, we need a working django-jet repo, where we can contribute as community and not depend on @f1nality, whom for whichever reason just doesn't care anymore or is unable to continue guiding it's development.
I have already fixed my code locally and made a working PR months ago, see: https://github.com/geex-arts/django-jet/pull/229
@SalahAdDin has contributed to a django-jetpack repo. I think we should update that repo and accept PRs there or elsewhere.
What do you think @SalahAdDin? Obiously to keep pingin @f1nality is not taking us anywhere. If we cant reorganize as community, I'll also have to remove jet in the future.
What do you think guys? Something needs to be done ASAP. :( But if @f1nality can't keep the boat afloat, maybe we should keep it afloat ourselves. Abandoning ship is not the only option.
I'm certaing that if we forked this repo and had someone like @SalahAdDin guide it we could succeed, the problems that need solving are:
- Just a couple of persons have write access here, solutions:
- convince @f1nality to add more people to the dev team.
- update django-jetpack or fork a new repo and contribute there, while we find a way to stay in touch and organized.
@dbortolz, @yalit, @FRReinert, @ilubnon, @SalahAdDin, @f1nality, @jelitox, @arbak, @thyagotosin, @zodman, @rbp
I'm pinging you because you where interested in this issue.
Please come to my Discord server so we can organize if you like:
- https://discord.gg/3yr5yeH
I'd like to try organizing a community around this project, before just forgeting about it at all.
Django-jet is cool, it just needs management, it already has a community of users, now we only need to organize!
If we can figure a way to keep things going forward, then I can start inviting everyone that has contributed or reacted to django-jet to the new project, watch for issues and PRs here, and tell people to please send those our way, etc. We can do this, I mean it.
I sincerely hope @f1nality is well and healthy, but I can't be in this situation anymore, something has to be done, cheers guys! 😄
In my Python/Django experience I've always known that customizing the admin interface is not an easy task, pushing the admin to the limits is risky. Generally speaking, I would not build an entire web app on the shoulders of the admin interface. If I have special needs I write down some plain Django CBV, it's a matter of minutes. django-jet it is really cool but thanks to a lot of custom JS and CSS, stuff I am not a fan of. You can enjoy its vanilla flavour-features without relying too much on it, if it's going to be a discontinued project. I hope it's not. Good luck to everybody.
@Ismael-VC, are you leaving the discord group?
Let me put my previous comment in perspective: it wasn't a threat, and I'm not sure a fork is necessarily the best solution.
This is FOSS, kindly written by @f1nality , and it's very useful - so much so that we're all here clamouring for more. I didn't mean to imply that he was doing a bad job, nor that he had any obligation to address our needs, and I'm sorry if I came across that way.
That said, there's clearly the need for faster development. A fork is always a possibility, but it's a somehow drastic one. Besides, who's to say that the fork will then keep on being developed? I'm sure @f1nality didn't plan on a hiatus, when he started this. Nobody is exempt from starting/picking up a project with the best intentions and then having to step away for a while, or drop it completely.
So, my suggestion to the people willing to take matters into their own hands is: reach out to @f1nality , and see if you can join as co-admins of the project. This immediately means more hands and eyes on the project, more PR reviewers, and hopefully a faster pace. It also means less fragmentation, and the continuation of what's after all a very nice project.
I'm in now way volunteering to do any of this - I have far too little time in my hands, and I've already forked django-jet to apply this fix. But I've seen way too many well-intentioned forks that end up as dead as the original project, and I hope we can avoid this here.
Best of luck!
@rbp You are right, my idea now, for now, is have a branch in our fork with this fixings and install this package from theme for awhile. @Ismael-VC What do you think about it?¡
I already remove jet from my projects.
Enviado do meu iPhone
Em 14 de ago de 2017, às 15:10, Ismael Venegas Castelló <[email protected]mailto:[email protected]> escreveu:
@dbortolzhttps://github.com/dbortolz, @yalithttps://github.com/yalit, @FRReinerthttps://github.com/frreinert, @ilubnonhttps://github.com/ilubnon, @SalahAdDinhttps://github.com/salahaddin, @f1nalityhttps://github.com/f1nality, @jelitoxhttps://github.com/jelitox, @arbakhttps://github.com/arbak, @thyagotosinhttps://github.com/thyagotosin, @zodmanhttps://github.com/zodman, @rbphttps://github.com/rbp
I'm pinging you because you where interested in this issue.
Please come to my Discord server so we can organize if you like:
- https://discord.gg/3yr5yeH
I'd like to try organizing a community around this project, before just forgeting about it at all.
Django-jet is cool, it just needs management, it already has a community of users, now we only need to organize!
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/geex-arts/django-jet/issues/161#issuecomment-322265301, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AYVNi0jP_a9Kt7dILS3aRcMHpvwUQlNcks5sYI2dgaJpZM4LXkG9.
@FRReinert Which alternative are you using now?
@SalahAdDin the discord server is there to stay! ;)
@rbp don't worry no one said your was a threat!
reach out to @f1nality
This has been done uncountable times, via email, github, you name it! I'm not saying django-jet is bad or that he did a bad job, but he does has abandoned the project, the django-jetpack fork is evidence of that.
In the begining I also told @SalahAdDin to try not to fork, to try to talk with @f1nality, just as you said, but that was months ago.
@SalahAdDin either has great patience or great expectations for @f1nality. I just want to move on.
I get what you say about the other fork could also die, and that's true, but django-jet is already dead, @f1nality is not going to give access to anyone else, nor answer or calls. There are other people who have also write access, judging by the commit log, but guess what, no answer or no way to contact them either.
I'm doing this not because, I hate anyone or am mad, I just really need to move forward, be it here or with an alternative, but I have already learned so much by reading django-jet source, taht I would like to document it even more, but not even that is accepted.
Jet is dead RIP, well this* repo is dead, the last time there was a merge to master was when this bug was introduced, no fix, no merge my PR, just anything.
If you guys want to keep waiting for him I understand, if you guys want to abandon ship I understand, but I'm going to try keeping a for up to date and accept PR's there before I thorw the towell.
Cheers!
Let's do it. Jet can't stop.
@SalahAdDin I can make you admin of the Discord server, just ask me! 😄
It still is happening inclusive after https://github.com/geex-arts/django-jet/commit/45e94712b35409652bf984bcadcdbc923c2ec2ae#diff-00db1b427cdf9ae5b3b45e603ae3225a
@arbak Do your solution create other buds?
That bug still occurs in the latest dev
Some one have a fix for it?
EY ey!! im investing this issue.... First:
at this moment the django-jet@dev its broken with django.jQuery because its not defined. issues related this: https://github.com/geex-arts/django-jet/issues/284 https://github.com/geex-arts/django-jet/pull/229
that was intruduce by this commit: https://github.com/geex-arts/django-jet/commit/a0d8b503af92eac9a3d1970b70212872f6b23149#diff-00db1b427cdf9ae5b3b45e603ae3225a
@Ismael-VC try to fix the select problem. To fix this issue and the django.jQuery error the correct solution its with:
#285
@Ismael-VC @SalahAdDin you are the most involved in django-jet checking the issues and PR plz check this and give me the approved with +1
@zodman, which one?
@SalahAdDin this comment https://github.com/geex-arts/django-jet/issues/161#issuecomment-360210596
I added custom select box to dashboard header and found this issue. This is what I did.
- Applied @arbak fix. In
admin/base.html
. - Then I've encountered "Uncaught RangeError: Maximum call stack size exceeded" issue.
Solution using JQuery (Could be done without it as well, of course). Issue happens because of infinite recursive function call. Just select your select box and on change
event stop propagation. This is an example.
jQuery('#my-select-box').on('change', function(e){
e.stopPropagation()
// needed actions
})
@emukans, @zodman, yes, this is a common error, if I'm not mistaken, that's why these code is using here.
I was having this problem with custom pages. To fix, I added two javascript files to extrahead
section on template:
{% block extrahead %}
{{ block.super }}
<script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/jquery.init.js' %}"></script>
{% endblock %}
Ps: Adding only the jquery.init.js
file generate the error Uncaught RangeError: Maximum call stack size exceeded
. So I added jquery.js
on top and all works. These files comes from Django code base.
@gabrielponto Ok, but, what is the problem behind this bug?
Why this 3-years old bug is not fixed today??? I have it on last version 1.0.8
Because @f1nality , the first author, left it.
:'(
Is there any chances that this bug will be fixed, although it has been 3 yrs ago.
remove the line
in select.js
$select.on('change', function(e) {
// django.jQuery($select.get(0)).trigger(e);
});
and make sure to create new bundle
all PR are well received.
Just saw this one on version 1.0.8
Uncaught TypeError: django.jQuery is not a function
at HTMLSelectElement.<anonymous> (bundle.min.js?v=1.0.8:1)
at HTMLSelectElement.dispatch (bundle.min.js?v=1.0.8:9)
at HTMLSelectElement.m.handle (bundle.min.js?v=1.0.8:9)
at Object.trigger (bundle.min.js?v=1.0.8:9)
at HTMLSelectElement.<anonymous> (bundle.min.js?v=1.0.8:9)
at Function.each (bundle.min.js?v=1.0.8:8)
at ot.fn.init.each (bundle.min.js?v=1.0.8:7)
at ot.fn.init.trigger (bundle.min.js?v=1.0.8:9)
at n.select (bundle.min.js?v=1.0.8:12)
at o.<anonymous> (bundle.min.js?v=1.0.8:12)
Never solved.
@SalahAdDin this PR works for me.
@SalahAdDin this PR works for me.
Thanks a lot, you saved my day.