2932

Coffeescript dynamically create/call a function from a list on select box value change

Question:

I'm working on adding some image editing tools using the <a href="http://www.pixastic.com/lib/docs/" rel="nofollow">Pixastic library</a>. The idea is that the user can choose an aspect of the image or tool they want from a select box, then the tool will show up below the select box (I'm using <a href="http://ivaynberg.github.com/select2/" rel="nofollow">select2</a>) and the user can edit via a slider. Here's what I have so far:

# This seeds the select2 options list imageToolsList = [ {id: 'bl', text: 'Blur'} {id: 'bc', text: 'Brightness/Contrast'} {id: 'ca', text: 'Color Adjust (RGB)'} ... ] #Creates a select box and calls imageTooler function when the value of the box is changed $(".image_tools_select").each -> $(@).select2 placeholder: "Select an adjustment tool." data: imageToolsList $(@).on("change", (i) -> imageTooler JSON.stringify( val: i.val clipName: $(@).closest('.clip').attr('id') ) ) # The function called on the value that the select box is changed to imageTooler = (i) -> imageData = jQuery.parseJSON(i) iId = imageData.val imageClipName = imageData.clipName newTool = "<div id=#{iId}><label>#{iId}</label><div class='slider#{iId}'></div></div>" $("##{imageClipName}").find(".imagetoolfields").append newTool

This succeeds in appending the name of the editing tool and the correct slider div beneath the select box when a tool is chosen, but what I'd really like is dynamically create a slider function for that particular tool and image (there are multiple images on a page, each with their own editing toolbelt). Here's a slider function that works for a the 'Blur' tool:

$('.sliderbl').slider min: 0 max: 5 value: 0.5 step: 0.1 range: "min" slide: (event, ui) -> $("#img_snapshot_16").pixastic("blurfast", {amount:ui.value})

Is there a way to expand the imageToolsList so that it looks something like:

imageToolsList = [ {id: 'bl', text: 'Blur', tool: $("##{imageClipName}").pixastic("blurfast", {amount:ui.value}), sliderVals: {min: 0, max: 5, value: 0.5, step: 0.1, range: "min"} } ... ]

and then dynamically create the jQuery slider functions for each tool in imageTooler, as is being done with the div and slider div?

Answer1:

Comments get a little tedious for anything complicated so I'll just go ahead and map it all out. I've made a few assumptions about what is defined where and when but I don't think the assumptions matter that much.

We'll start with a simplified case: just one object similar to what you have in imageToolsList:

{ id: 'bl' text: 'Blur' sliderVals: { min: 0, max: 5, value: 0.5, step: 0.1, range: "min" } tool: (imageClipName) -> (event, ui) -> $("##{imageClipName}").pixastic("blurfast", {amount:ui.value}) }

I've tweaked the order a little bit and switched tool to a function which returns a function. We don't want the pixastic call to happen while you're defining the object literals in imageToolsList, making tool a function allows us to defer the pixastic execution until later. Since we (presumably) don't know what imageClipName should be when we define imageToolsList, we need another function to allow us to fill that in with, again, calling pixastic until even later; hence the function returning a function trick.

Given one of these, how do we build a slider call? All we need to do is copy sliderVals (to avoid changing imageToolsList) and fill in the slide function:

sliderDef = { id: 'bl', ... } doTheSliderThing = (imageClipName) -> slide = sliderDef.tool(imageClipName) args = $.extend({ }, sliderDef.sliderVals, slide: slide) $(".slider#{sliderDef.id}").slider(args) # And make it all go and pixastic-ify `#pancakes`. doTheSliderThing('pancakes')

tool is a function which returns a callback function so sliderDef.tool(imageClipName) gives us the appropriate

(event, ui) -> $(...).pixastic(...)

callback function.

If we have an id and we want the appropriate entry from imageToolList, then we have to go looking for it:

# If the list is short: [sliderDef] = (o for o in imageToolList when o.id == id)

The <a href="http://coffeescript.org/#loops" rel="nofollow">for loop</a> gives you an array back and then the <a href="http://coffeescript.org/#destructuring" rel="nofollow">[sliderDef] unwraps that array</a> and leaves the single result in sliderDef. If the imageToolList is longer then you'd want to short-circuit the loop and bail out as soon as you have a result:

# Longer list, bail out as soon as we've found what we're looking for. for o in imageToolList when o.id == 2 sliderDef = o break

or better, rework the structure of imageToolList to allow direct access by id:

# Even longer list: allow direct access by `id`. imageToolList = bl: { text: 'Blur', sliderVals: { ... }, ... } ...

and then we can do things like this:

doTheSliderThing = (id, imageClipName) -> sliderDef = imageToolList[id] slide = sliderDef.tool(imageClipName) args = $.extend({ }, sliderDef.sliderVals, slide: slide) $(".slider#{id}").slider(args) # And make it all go and pixastic-ify `#pancakes` using `'bl'`. doTheSliderThing('bl', 'pancakes')

Or, if you prefer to be terse:

doTheSliderThing = (id, imageClipName) -> $(".slider#{id}").slider($.extend({ } imageToolList[id].sliderVals slide: imageToolList[id].tool(imageClipName) )) <hr />

<strong>Update for the comments</strong>: If you have this:

sliderDefs = bl: { text: 'Blur', sliderVals: { ... }, ... } ...

Then you can build the stuff that slider2 wants like this:

opts = ({id: k, text: v.text} for k,v of sliderDefs)

Recommend

  • NullPointerException on PLAF change to Motif
  • Swift POST Request in same Thread
  • Print a diamond shape with a borderusing asterisks in C/C++
  • SAS concatenate in SAS Data Step
  • OLAP cube design reference for a IT support business [closed]
  • How to plot a filled circle?
  • Rcpp Armadillo: RStudio says “exp” is ambiguous
  • How to load and fill cubes with texture image in openGL
  • Returning multiple rows from a single row
  • Viola-Jones Algorithm - “Sum of Pixels”?
  • Prefix to Infix Conversion Algorithm with figure
  • jQuery Datatable: pagination and filter not display correctly
  • MFMailComposer not working in io6 landscape mode
  • C# equivalent to VB6 'Type'
  • Paper.js Loading Images and the Active Layer
  • Start X server on Google Cloud (Debian) Compute Engine
  • visualizing RDF query result
  • Deleting in NSDocumentDirectory
  • How to execute two asynchronous functions sequentially
  • winrt, javascript, image from byte array
  • In struts1.2 how to populate dropdown according to database value
  • What is the fastest way to select nearest geographical place from mysql database?
  • Reverse output of polyfit numpy
  • GridBagLayout padding
  • jquery code not working without breakpoint
  • How to make R's read_csv2() recognise the text characters properly
  • SAVE attribute needed for Fortran variables when only the C_LOC address is returned to a C program?
  • saving file generated by TCPDF
  • d3 v4 drag and drop with TypeScript
  • jQuery tmpl and DataLink beta
  • Why winpcap requires both .lib and .dll to run?
  • How to disable jQuery.jplayer autoplay?
  • CSS Applying specific rule for a specific monitor resolution with only CSS is posible?
  • How to set the response of a form post action to a iframe source?
  • Setting background image for body element in xhtml (for different monitors and resolutions)
  • Are Kotlin's Float, Int etc optimised to built-in types in the JVM? [duplicate]
  • unknown Exception android
  • Observable and ngFor in Angular 2
  • UserPrincipal.Current returns apppool on IIS
  • java string with new operator and a literal