I might be so bold as to think that some jQuery user, would appreciate to be able to do this :
1 2 3 4 5 6 |
$(<span style="color: #006080;">'#container[~top]'</span>) <span style="color: #008000;">// inside id='container' select elements with 'style.top' present </span>$(<span style="color: #006080;">'#container[~top!=auto]'</span>) <span style="color: #008000;">// even more usefull: disregard top if its value is 'auto' </span>$(<span style="color: #006080;">'#container[status!=employed]'</span>) <span style="color: #008000;">// attribute selection same as before</span> |
There are several plugins that implement this idea of selecting by style properties too. Let me remind you , that both attributes and css properties objects exhibit W3C Attr interface. Aka DOM Attribute node. This fact is never made obvious explicitly in the spec, but both are nothing else but name/value pairs. Can you see that? I am sure you can. What is the purpose of the above ‘~’ selection extension ? The purpose is to be able to operate on css properties and attributes, uniformly, as on NAME-VALUE pairs. To be able to treat them both as a single abstraction, as the “name/value pair” abstraction. Why? So that one can program her own OPERATORS to operate on these values. As functoids of course. Imagine an jQuery plugin called ‘formula’. Its purpose is for users to be able to change values of name/value pairs using an user defined equation, or formula. For this to happen we need to select some name/value pair and then we need to pass them all to the formula. Imagined usage :
1 2 3 4 5 6 7 8 9 10 11 |
<span style="color: #008000;">// move everything that is movable and inside the id=container element</span><span style="color: #008000;"> // for 100 units to the right</span> $(<span style="color: #006080;">"[~top!=auto]"</span>,<span style="color: #006080;">"#container"</span>).formula( function ( old ) { <span style="color: #0000ff;"> return</span> old.<span style="color: #0000ff;">value</span> + 100 + old.unit ; }); <span style="color: #008000;">// in the current table, change status of all employees which are // older than 50 // then color their names in red </span> $(<span style="color: #006080;">"[status=employed]","#people_table"</span>).formula( function ( old ) { <span style="color: #0000ff;"> </span> old.status = <span style="color: #006080;">"sacked"</span>; }).css("color", "red"); |
formula()
method is passed one argument, which is an json object. Which is made from attributes or style.properties as named in the selector. Format of this argument passed should be something like this :
1 2 3 4 5 6 7 8 9 10 11 12 |
{ owner: element, name : <span style="color: #006080;">"top"</span> , <span style="color: #0000ff;">value</span> : <span style="color: #006080;">"20"</span>, unit : <span style="color: #006080;">"px"</span> } <span style="color: #008000;">// made from owner element.style.top : "20px"</span> { owner: element, name : <span style="color: #006080;">"top"</span> , <span style="color: #0000ff;">value</span> : <span style="color: #006080;">"auto"</span> , unit : <span style="color: #006080;">""</span> }<span style="color: #008000;"> // made from owner element.obj.style.top : "auto"</span> { owner: element, name : <span style="color: #006080;">"data"</span> , <span style="color: #0000ff;">value</span> : { age: 51, name: <span style="color: #006080;">"John"</span>, sallary: 1, status: <span style="color: #006080;">"architect"</span> } , unit: <span style="color: #006080;">""</span> } <span style="color: #008000;">// made from the data attribute</span> |
And now the very interesting part. The value the function given to ‘formula()’ changes in the argument, is given back to the owner element. That is the value, and unit are changed on the owner element, after formula() worker has done its job. The new value is saved back to its attribute or style property. Compared to current code that uses ‘css()’ and ‘attr()’ this looks like an improvement.
Consider this requirement: “Using jQuery, make an element to fly (move) in a circle around a centre of the page”. I am sure you can think of an solution using css(“top” …) and css(“left” …. ) etc. Or even no jQuery. But that would be very painful. Centre of the element must be on the circular path, not its upper left corner, etc. Much more elegant to code with the ‘formula’ method:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<span style="color: #008000;">// Circle equation: sqr(x) + sqr(y) = sqr(R) </span><span style="color: #008000;">// where Center is at the origin : 0,0 </span>function circular_movement ( center_point, radius, sprite ){<span style="color: #008000;"> // calculate next X for the point on the circle</span><span style="color: #008000;"> // leave the result in the 'style.left' property </span><span style="color: #0000ff;">this</span>.circleX = function (old) {} <span style="color: #008000;">// calculate next Y for the point on the circle</span><span style="color: #008000;"> // leave the result in the 'style.top' property </span><span style="color: #0000ff;">this</span>.circleY = function (old) {}<span style="color: #008000;"> // do this repeatedly in predefined steps </span>$(<span style="color: #006080;">"#sprite[~top]"</span>).formula( this.circleY ) ; $(<span style="color: #006080;">"#sprite[~left]"</span>).formula( this.circleX ) ; } |
I think using ‘formula’ will give me much cleaner and shorter code. This discussion suggests an fundamental behavioural change. Now all I have to do is to think how to implement it in some “awesome” way.
2 thoughts on “jQuery name/value pairs and operations on them”
That’s a very nice pattern! You can also generalize these “mutator functions” so they can be applied in multiple scenarios and the actual property (and setter function) will be only determined later based on the selector — it’s very elegant!
But I think you’d better use $(“#sprite[~top!=auto]”); instead, the script I sent you works that way too!
Ok, I will work on the whole idea more. Also: “formulas” are javascript functions, which are reusable, you are right. Very similar to c++ std (aka stl) “functors”. Consider this example: