Posts tagged jquery

Looping through the Matrix

Anyone out there use ExpressionEngine? Okay, settle down. Anyone use Pixel & Tonic’s Matrix field type? Likely that the same number of people just raised their hands. Now, how many of you custom-dashboard-matrix-using-expression-engine developers also use jQuery?

That should have been everyone as well.

One of the challenges we run into at the office is looking at the values of a Matrix field to compute, compare or validate on. For example, one might have a matrix with this format column format:

Item Description | Price

Very simple data entry example. Item and Price. At any time you might want to get an updated Total Price number to the end user. Looping over the entire Matrix is the pain point we found a nice solution to. Take this jQuery snippet as our reference bit:

    $('div#field_id_106 textarea.matrix-textarea[name^="field_id_106[row_"]').filter('[name*="[col_id_38]"]').each(function() {
        // Do some cool stuff here with the data. Access the local cell with
        // $(this).val()
    });

The jQuery warriors among us are saying “Well, yeah, duh!”. The rest of us are looking at Sanskrit. The magic are the name^= and the name*= selectors. First, we select down to the Matrix we care about. In my example, it is contained inside of div#field_id_106. Next I select down to the textarea stuff, since the fields I care about here happen to be textarea fields. Now for some magic.

[name^="field_id_106[row_"]

The operator ^ after the name attribute tells us that the selector we are isolating down to must START with the string field_id_106[row_ in order to be included. Stopping at the row_ is a trick that really made this useful for us. Both NEW matrix rows as well as UPDATE matrix rows (existing values in place) will contain this. You won’t need to know anything about the matrix you are looking at in order for this selector to work.

Last I add the .filter() to our object. This filters further to look at a specific column in the Matrix. I take advantage of the * operator here (can contain ANYWHERE), and I look for the [col_id_38] string in the name attribute. We wrap it up with the .each() call, and now we have a nicely set loop. Within the loop we can get to our cell values with:

$(this).val()

There are going to be a lot of ways to slice this turkey, and I would love to hear from anyone else that has faced this issue. Are there even cleaner ways to get into the Matrix cells via jQuery?


• • •

The jQuery, The Link and The Target

I received an e-mail yesterday evening from someone using some old ExpressionEngine plugin of mine.  Specifically it was Rewrite Links, and I have long since orphaned this.  The story behind this plugin was that my content people did not consistently use target=”_blank” for outbound links.  At the time, ExpressionEngine was new to me and I was trying to use it as the hammer for every nail I found.

That was a dumb way to go.  About a month later I found several bugs with the methodology and realized the code path was fundamentally flawed.  As I am still in denial about making such a poor engineering choice so I will avoid discussing what I messed up and move on to my solution.  Long story short, the above e-mailer had run into these bugs as well and was curious if I had seen and solved them.

I am getting rather good with jQuery.  Good enough to be dangerous anyways.  My solution for some time has been a little jQuery snippet in my footer.  The absolute minimal approach is to stick this at the end of the page (or in a $(document).ready() call):

  $("a[@href^='http']").attr('target', '_blank');

This bit looks at all the A tags in the page, then filters down to tags with the characters http in the href attribute.  All results get target=”_blank” added to them.  Very simple, fast and effective.  We can even expand the concept a bit in a number of ways.  Most useful to me has been to use the .each() iterator with it.

  $("a[href^='http']").each(function() {
    if( $(this).attr('href').indexOf('localdomain.com') < 0 ) {
      $(this).attr('target', '_blank');
    }
  });

This is getting to be a pretty powerful bit of code.  Going back to my content people, they all seem to use different types of links for on-site stuff.  Some of them use a relative path.  Some of them use absolute paths.  Some of them use absolute paths without the WWW. in front of our domain.  We force that in our .htaccess file.  The above snippet applies this logic:

  • All link tags
  • That contain http
  • That do NOT contain localdomain.com
  • Add the attribute target=”_blank”

This has proven to be pretty effective for us.  It is important to leave out the WWW. from your localdomain.com in the IF conditional.  Some users will use it, some will not.  Your site might force WWW, it might force NON-WWW, or it might not care.  By using the 2nd level naming only and dropping the 3rd, you will get what you intend with less fuss and failures.

If you really REALLY wanted to, you could even replace the hard-coded ‘localdomain.com’ string with document.domain.  To keep things sane, just check for and truncate any WWW. from the return and you have code you never need to touch.

Maybe something kewl like this, tossing some :not() selectors into the mix:

  $("a[href^='http']:not(a[href^='http://" + window.location.host.toLowerCase() + "']):not(a[href^='http://www." + window.location.host.toLowerCase() + "'])").attr("target", "_blank");

• • •