Approaching jQuery popup callback hell

I wrote this post on the jQuery mailing list and nobody replied, so I’m pasting it here. I could really use some advice.

I’m using a modal dialogs and I love them, but I haven’t found a really elegant way to handle actions in the dialog window that require changes to the parent page.

Here’s an example. I have a monthly calendar page that lists employee names on the days they are supposed to work. Clicking on an employee name opens a “shift detail” page in a modal dialog.

That shift detail page has more information like the specific tasks planned for the day, the start time and stop time of the shift, etc. From this shift detail screen, I can remove this particular employee from the schedule by submitting an AJAX POST from this popup.

After I remove the employee, I need to update both the popup window and the original page that hosted the link to the popup window. Right now I do this by adding a callback that fires when the AJAX POST succeeds. That callback then updates both pages. The callback is named “after_remove_employee”.

This system gets really nasty when I use the “shift detail” popup on different screens. For example, in addition to the monthly view, I also have a weekly view with more information. So after an employee is removed from the schedule on the weekly view, I need to do some different things in the callback.

Right now, the way I handle this is that I define the same callback twice. I define “var after_remove_employee = function (data) {…} on the weekly view to do what it needs there, and then I define it differently on the monthly view.

I’ve simplified the problem to help explain it. In reality, I have lots of different popups on lots of different pages, and in each popup, there are many different possible actions.

I’m sure I’m not the only one that’s been in this scenario. What is an elegant solution?

I’m thinking about using custom events. So, the callback after a successful AJAX POST would just fire an “employee removed” event, and everybody subscribed would get a reference to the event object and do whatever they want.

However, I’ve never used JS events before, and I don’t know if this is even possible.

Please, any feedback is welcome.

virtualenvwrapper postactivate and screen is a wonderful combination

I switched to virtualenvwrapper from plain old virtualenv a while back because I found out that virtualenvwrapper has a postactivate hook I can define. Now when I do

$ workon pitz

to start my work day, I get a customized work environment exactly the way I want it. In addition to activating a virtualenv named pitz, the postactivate script changes me into the top of my pitz checkout directory and then it starts up or reattaches a screen session customized just for pitz.

Setting this up was trivially easy. Here’s what my postactivate script looks like:
$ cat ~/.virtualenvs/pitz/bin/postactivate
cd /home/matt/projects/pitz
screen -S pitz -c ~/.screenrc-pitz -d -R

And here is that .screenrc-pitz file:
$ cat ~/.screenrc-pitz
# Matt's homemade .screenrc.

# Draw that blue and red bar across the bottom of the terminal, with the cute
# stuff like the window names and system CPU load.
hardstatus on
hardstatus alwayslastline
hardstatus string "%{.bW}%-w%{.rW}%n %t%{-}%+w %=%{..G} %H %l %{..Y} %m/%d %C%a "

# Let me scroll back a thousand lines or so.
defscrollback 1024

# terminfo and termcap for nice 256 color terminal
# allow bold colors - necessary for some reason
attrcolor b ".I"

# tell screen how to set colors. AB = background, AF=foreground
termcapinfo mlterm 'Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm'

# erase background with current bg color
defbce "on"

# Automatically start up a bunch of windows.
screen -t "shell" 0 pitz-shell
screen -t "code" 1
screen -t "tests" 2
chdir docs
screen -t "docs" 3

Everything from the top down to the comment # Automatically start up a bunch of windows. just tweaks how screen works. The last part creates a bunch of named windows. In the first wiindow, it doesn’t start a bash prompt. Instead it starts up the pitz-shell.

One tiny detail that may not be obvious is that if I do $ workon pitz in one terminal, and then maybe I ssh in and rerun $ workon pitz again later, I won’t cause a second screen to start up. Instead, I’ll remote-detach the original session and reconnect to it.

In practice, all my remote servers have highly customized screen sessions already waiting for me. I just need to log in and resume them, and I have all the interesting log files, database connections, and monitoring scripts already up. For example, I know my apache log is open in a pager in window 5. Window 2 has a psql session running. Window 1 has a supervisorctl client running.

This setup shaves off precious seconds when I’m trying to figure stuff out during an emergency.

This stuff isn’t rocket science, but I hope it helps somebody out.

How I cook kohlrabi

I like to cut kohlrabi into matchsticks of about a quarter inch wide. Sometimes I peel off the outer layer because it can be too fibrous.

I dump the match sticks into already-boiling water and cook for about 10-14 minutes, or until I like the texture. I constantly snack on the matchsticks while cooking them.

Once they’re soft enough, I drain it all through a colander and then put everything back in the pot and add a few tablespoons of butter, salt, pepper, and maybe some parmesan cheese, and maybe some red pepper flakes.

If you got it with the leaves, they can be cooked like greens. When my parents were in town, my mom cooked the leaves like this:

  1. cook some onions in butter
  2. chop and steam greens separately
  3. add some sugar and vinegar to the onions
  4. throw in the greens and stir them around

In conclusion, kohlrabi is an underrated vegetable.

Python niceties

nicety (plural niceties)

  1. A small detail that is nice or polite to have but isn’t necessary.

Make a comma-separated string

>>> x = ['a', 'b', 'c']
>>> ', '.join(x)
'a, b, c'

Isn’t that prettier than some big loop?

If you want to join a list of elements that aren’t strings, you’ll have to add a step:>>> x = [1, 2, 3]
>>> ', '.join(map(str, x))
'1, 2, 3'

I’m using map to convert every element to a string first.

Choose a random element from a sequence

>>> from random import choice
>>> choice(x) # doctest: +SKIP

The doctest: +SKIP text is just there because the element returned is randomly chosen, and so I can’t predict what the value will be.

Use keyword parameters in your larger string templates

Well-named keywords make big string templates MUCH easier to deal with:>>> tmpl = """
... Dear %(display_name)s,
... Greetings from %(origin_country)s! I have millions of
... %(currency_type)s in my bank account and I can send it all to you if
... you first deposit %(amount)s %(currency_type)s into my account
... first.
... Sincerely,
... %(alias)s
... %(origin_country)s
... """

Seeing the key names makes it much easier to remember what gets interpolated. Also, it makes it easier to use the same values more than once.

Usually I pass in a dictionary to the template, but sometimes I do this instead:>>> display_name = 'Matt'
>>> origin_country = 'Nigeria',
>>> currency_type = 'US dollars'
>>> amount = '250.00'
>>> s = tmpl % locals()