Giter Club home page Giter Club logo

jayq's Introduction

jayq

Clojars Project

A jQuery wrapper for ClojureScript.

Wait a second.. I thought we weren't supposed to use jQuery?

When ClojureScript first came out, the prevailing wisdom was that since jQuery wasn't compatible with the Google Closure Compiler, we shouldn't be using it. So I set off to work on Pinot, a library that wrapped the goog.* APIs. The journey was painful and frustrating, and before long I realized I was essentially rewriting parts of jQuery for no gain. Instead of doing that, I figured my time would be better spent building on top of the most battle hardened JS library out there. Before I started down this path though, I wanted to make sure that I had answers to all the arguments against using it. They were as follows:

  • It can't be compiled by the Closure compiler and means we can't use Advanced compilation.
  • It will add another thing for you to download and increase the size of the cljs code, because the symbols won't be munged by the Closure compiler.
  • It won't lend itself to Clojure idioms.

I'll tackle each of these in order.

In terms of it not being able to be compiled, we shouldn't be packaging jquery with our apps anyways. Virtually the entire web is built on $ and that means nearly every computer connected to the internet already has a google CDN'd version of jquery on their machine. That means there's no extra weight and no reason to compile it. This also addresses the first part of the second one - there's nothing more to download.

While it's true that if we used jQuery directly, all method calls would be left alone and could not be replaced with a minified name. With a wrapper, however, that happens exactly once per method and all occurences of the wrapper will be munged. This means that at most we're talking about a difference on the magnitude of bytes. If you need to optimize for size at that level, you shouldn't be using CLJS anyways.

Lastly, there's the argument that it won't lead to idiomatic usage. That's likely true if we use jQuery directly, but I'm not sure I really believe that's a valid argument. The same goes for Clojure if we use Java libraries directly all over the place. Wrappers, however, allow us to utilize all the functionality provided by these libraries, but still create Clojure idioms over top of them. There's no reason to ignore the most solid base out there, when we can just build greater abstractions on top of it. Do I think jQuery is the pinnacle of the client side web? Not at all, but I do believe it provides a great foundation for us to build exactly that.

Installation

Add the following to your project.clj

[jayq "2.5.4"]

Note: If you are upgrading to a major version be sure to check the changelog for breaking changes.

Usage

jayq.core Source

Most of the API in jayq.core maps 1:1 with jQuery functions.

(ns myapp
  (:use [jayq.core :only [$ css html]]))

(def $interface ($ :#interface))

(-> $interface
  (css {:background "blue"})
  (html "Loading!"))

jayq.core/ajax clojure & edn mime types support

Requests with :contentType option matching text/clojure text/edn application/clojure application/edn (as string or keyword) will have the :data turned into its string representation (via pr-str)

Responses with text/clojure text/edn application/clojure application/edn mime types are read as clojure data before being passed to callbacks. The same applies if the dataType option is set to :edn or :clojure.

jayq.util Source

  • jayq.util/log [value & text] : console.log wrapper

  • jayq.util/wait [ms f] : setTimeout wrapper

jayq.macros Source

  • jayq.macros/queue [elem & body] : a wrapper of jayq.core/queue that includes the lambda with a scoped this symbol

  • jayq.macros/ready [& body] : a wrapper of jayq.core/document-ready

  • jayq.macros/let-ajax [steps & body]: let like form allowing chaining of ajax calls and binding return values to locals for use once all the calls are complete (or in a :let intermediary step). The step value expected is a valid jq.core/ajax request map. You can supply :let/:when steps (like in for/doseq) between "regular" steps.

(let-ajax [a {:url "http://localhost:8000/1.json"
              :dataType :json}
           b  {:dataType :json :url "http://localhost:8000/2.json"}]
       (merge a b))
  • jayq.macros/let-deferred [steps & body]: let like form allowing chaining of deferreds and binding return values to locals for use once all the deferreds are realized (or in a :let/:when intermediary step). The step value expected is anything that returns a deferred instance. You can supply :let/:when steps (like in for/doseq) between "regular" steps.
(let-deferred
    [a (jq/ajax "http://localhost:8000/1.json")
     :let [foo "bar"]
     :when (= (concat a foo) "foobar")
     b (jq/ajax "http://localhost:8000/2.json")]
(merge a b foo))
  • jayq.macros/do-> [m-specs steps & body]: let-* macros are built from it. m-specs is a map of :bind and :return functions that dictate the workflow (see: jayq.core/deferred-m and jayq.core/ajax-m).

Error handling in let-ajax and let-deferred forms should be done using jq.core/fail or the :error key on the request map.

Changelog

See CHANGELOG.md

Compiling

If you're using advanced Clojurescript compilation you'll need to reference a jQuery externs file.

You can find externs files from the closure-compiler repository for a specific jQuery version.

Add this to your compilation options (assuming that your put the externs file in ./externs/):

  {
    :optimizations :advanced
    :externs ["externs/jquery.js"]
    ...
  }

Without this, you will see errors like Object ... has no method XX. See http://lukevanderhart.com/2011/09/30/using-javascript-and-clojurescript.html for more on externs.

License

Copyright (C) 2011 Chris Granger

Distributed under the Eclipse Public License, the same as Clojure.

jayq's People

Contributors

bobby avatar bostonaholic avatar ekarlsso avatar emidln avatar frankhale avatar gfredericks avatar glittershark avatar hsalokor avatar iamjarvo avatar ibdknox avatar jsyrjala avatar krisajenkins avatar mot-horloge avatar mpenet avatar paulcarey avatar petrglad avatar rovanion avatar suweller avatar torbjornvatn avatar zachcurry avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jayq's Issues

Use jayq as jQuery in external libraries

I am using https://datatables.net which has a dependency of jQuery which ofcourse I want to avoid as I am using Reagent. I am including the library in my project through :foreign-libs. I get an error saying jQuery is not defined from the dataTables.js, which is due to the library using jQuery instead of $ and being called before jayq.
Do you have an idea of a workaround this problem? It would be amazing if this can be achieved and jquery can be removed completely.

Equivalent of $(this)

A frequently used pattern in JS callbacks is $(this), and an equivalent would be useful in jayq. I have successfully used ($ (js* "this")) to do this and wondered if ($ :this) would be a sensible alias ?

clj->js is now supported in clojurescript...

Since one month or so, the clojurescript runtime has its own version of clj->js, which seems to be compatible with the one provided by jayq.

Unfortunately, the name clj->js clashes as jayq use a "use" clause to incorporate clj->js in its core.cljs.

Not sure what the best way is to go about this.
I simply commented-out any reference to jayq.utils/clj->js such that the clojurescript version is used, but that will not work for anyone relying on older cljs-versions.

Maybe conditionally require when the cljs-version is "old" (?)... but there is no "cljs-version" var/fn...

Maybe only require/define if the clj->js var hasn't been interned yet (?).

Any better/alternative resolution?

-FrankS.

Undeclared vars when compiling

Happens at least with [jayq "0.1.0-alpha2"] and [jayq "0.1.0-alpha3"] (which seems to be the latest version).

WARNING: Use of undeclared Var jayq.core/coll at line 58 .lein-cljsbuild-compiler-1/jayq/core.cljs
WARNING: Use of undeclared Var jayq.core/coll at line 60 .lein-cljsbuild-compiler-1/jayq/core.cljs
WARNING: Use of undeclared Var jayq.core/i at line 60 .lein-cljsbuild-compiler-1/jayq/core.cljs

clj__GT_js Undefined after Upgrade to 2.1.0

After upgrading to jayq to 2.1.0 and cljsbuild to 0.3.0 I'm getting the error:

jQuery.ajaxSetup(jayq.core.clj__GT_js.call(...)
Uncaught TypeError: Cannot call method 'call' of undefined

I previously encountered this error when using a pre-2.1.0 version of cljsbuild. Is my current issue dependency related as well?

Pending pull requests are being ignored?

There are 3 pull requests pending. It'd be awesome if somebody could take a look. I've been using my fork instead of upstream because patches are not being applied in a timely manner to fix issues on newer versions of the Clojurescript library.

Release latest fixes?

2.5.0 doesn't contain the fixes for $ namespace warnings, is there a plan for an updated release?

jquery .ready

I'm wondering what's the best way to wait for the DOM to load with jayq? The standard jquery way is either:

$(...)

or

$(document).ready(...)

The first form would seem to translate to this:

($ (fn [] ...))

but that doesn't seem to work, I think because when a function is passed as the first param to $ it's assumed to be a crate function and some special handling happens. This works, however:

(.ready ($ :document) (fn [] ...))

but it's a little verbose. What would you think of a (ready ...) macro?

Very cool library by the way! It's nice to be able to use jQuery in clojurescript so easily!

(inner $elem v) should call .html ?

When I tried (inner ($ :#foo) "stuff") I got a JS exception that $elem had no function innerHTML.

If I call (.html ($ :#foo) "stuff") it works...

jayq.core.data doesn't follow jQuery API

I believe this would match the jQuery API

(defn data
  ([$elem] (.data $elem))
  ([$elem k] (if (map? k)
                 (.data $elem (clj->js k))
                 (.data $elem (name k))))
  ([$elem k v] (.data $elem (name k) (clj->js v))))

which jquery-version is compatible with jayq 0.2.0?

when reading the externs.js it says it's made for jQuery 1.7. The current release of jQuery is 1.8.2. Should I use the latest version of jQuery (1.8.2) or some 1.7 version?

It would be great if this info was availiable in the readme, since Jayq would be even more epic then!

Thanks,

Publish new release to Clojars

This is a placeholder issue because we need a new release made on Clojars as there have been several patches over the last couple years (since last release). I published the last release but have totally forgotten how to do it. I'll have to go back and relearn (LOL!). If anyone has any info they can share feel free to leave a comment.

Mentioning of "externs" field in README

I got a problem with jayq and :advanced optimizations:

Uncaught TypeError: Object function (a,b){return new e.fn.init(a,b,h)} has no method 'U'

Thanks for #clojure@freenode guidance, I've solved it adding :externs ["externs/jquery.js"] to my project.clj. Would you mind adding this caveat to README?

inner and not html?

Why is there no "html" function, and one called "inner" that is not found in the current jQuery API?

Certain functions cause app to fail uberjar

When packaging a Reagent app into an uberjar, I found that any namespace that used Jayq, or referenced another namespace that used Jayq, failed compilation. I was requiring $, css, and so forth. My project.clj does include Prismatic/dommy and domina. Not sure what dependency issue might have caused this.

Adding elements to a HTML select using append, attr and text chained.

This is likely not the place to post this but I'd like to see if this is an issue or the fact that I'm just misunderstanding how to use jayq.

I've got a HTML select that I'd like to append options to, I've binded it to a change event and the following code will not add new elements. Am I misunderstanding how to use this?

(defn create-option [elem val]
    (-> elem
        (jq/append "<option></option>")
        (jq/attr {:value val})
        (jq/text val)))

elem is the select list which and val is the value I'd like to use for the option.

Note: I have a work around that just uses the append and a interpolated string and that works but it's less nice. I'd rather do it like I am above which is more Clojurey.

Any assistance would be greatly appreciated.

Unable to require jayq.macros

Requiring the jayq.macros namespace fails compilation.

(ns myapp.app
  (:require [jayq.core :as jq]
            [jayq.macros :as jqm]))
Compiling "resources/assets/cljsbuild-main.js" from ["src-cljs"]...
WARNING: No such namespace: jayq.macros at line 1 src-cljs/myapp/app.cljs
WARNING: Required namespace not provided for jayq.macros
Successfully compiled "resources/assets/cljsbuild-main.js" in 0.237 seconds.

This is version 0.0-2173 of clojurescript.

Using text to retrieve values

Hi,

I'm trying to use jayq's text function to retrieve a value like this:

(defn ^:export setLetterDetail [td]
   (let [$link (find ($ td) "a")]
   (inner ($ :#letterDetail) (text $link))))

But it doesn't work.

When I debug the js-file I can see that jayq.core.text is called with the link as first parameter, but undefined as the second.

Any hints to how I could awoid this (apart from using a dot in front of text)

/torbjørn

Problem with advanced compilation

The following very simple project runs successfully when compiled with :optimizations :simple
https://github.com/djpowell/jqproblem

But when compiled with :optimizations :advanced, it fails at the line:

(j/add-class elt "hey")

with the exception:

main.js:82Uncaught TypeError: Object [object Object] has no method 'N'
  Zbmain.js:82
  $bmain.js:82
  (anonymous function)index.html:18
  onload

Any ideas what might be wrong?

It will build and run with

lein deps
lein cljsbuild once
resources/public/index.html

TypeError: jayq.core.X is undefined errors

I have the following errors:

TypeError: jayq.core.prevent is undefined
TypeError: jayq.core.on is undefined

but using respectively .preventDefault and .on fixes them.

It would seem I cannot access these forms under jayq.core, but I can use its bind and $.

Project dependencies: [noir-cljs "0.3.7"] and [jayq "2.3.0"]

Up until now these issues are not fatal, but it would be good to know what's happening.
Thanks.

Is the "text" function broken for a single argument?

So I am new to clojure and clojurescript, so I am not sure if this is a bug or misuse of the text function but here is the problem:

(.text ($ :#my-selector))

Works as intended, but this does not (that uses jayq)

(text ($ :#my-selector))

WARNING: Wrong number of args (1) passed to jayq.core/text at ...

If I am using this wrong, I apologize, but let me know if this is an issue and I can try and fix it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.