SeattleStephens
SeattleStephens

Reputation: 587

No javascript provider is configured

Update: I've isolated this error to registering the onchange event in this select. If I remove the onchange, the page renders without error, otherwise I get the No javascript provider error.

<g:select optionKey="id" optionValue="name" name="course" id="course"
   from="${com.TourneyCard.Course.list(sort:'name')}" value="${homeCourse.id}"
   onchange="${remoteFunction(controller:'foursome', action:'ajaxGetTeesJSON',
     params:'\'id=\' + escape(this.value)', 
     onSuccess:'updateTees(data);')}">
</g:select>

For various reasons I'd like to include jQuery using the resources Plugin instead of the the jQuery Plugin. It's mostly working but I have a page that will not render and is instead issuing the error No javascript provider is configured.

My ApplicationResources.groovy defines jquery:

jquery {
    resource url: 'js/jquery/jquery-1.9.1.min.js', disposition: 'head'
}

My main.gsp layout looks like this:

<head>
    <g:layoutHead/>
    <g:javascript library="jquery"/>
    <r:require module="jquerymobile"/>
    <r:layoutResources />
</head>

The page issuing the provider not configured error looks like this:

<head>
    <meta content="main" name="layout">
    <r:require modules="jqmdatebox,jqmgrid960,updateTees"/>
    ....
</head>
<body>
    ....
    <g:javascript>
        var zselect = document.getElementById('tee')
        var zopt = zselect.options[zselect.selectedIndex]
    </g:javascript>
</body>

Upvotes: 1

Views: 2787

Answers (5)

D&#243;nal
D&#243;nal

Reputation: 187529

This solution worked for me:

Add the following class (from the jquery Grails plugin) to your application

import org.codehaus.groovy.grails.plugins.web.taglib.JavascriptProvider

class JQueryProvider implements JavascriptProvider {

    /**
     * doRemoteFunction creates a jQuery-AJAX-Call
     *
     * @param taglib
     * @param attrs
     * @param out
     *
     * @return the jQuery-like formatted code for an AJAX-request
     */
    def doRemoteFunction(taglib, attrs, out) {
        // Optional, onLoad
        if (attrs.onLoading) {
            out << "${attrs.onLoading};"
        }

        // Start ajax
        out << /jQuery.ajax({/

        // Method
        def method = (attrs.method ? attrs.remove('method') : 'POST')
        out << "type:'$method'"

        // Optional, synchron call
        if ("false" == attrs.asynchronous) {
            out << ",async:false"
            attrs.remove('asynchronous')
        }

        // Optional, dataType to use
        if (attrs.dataType) {
            out << ",dataType:'${attrs.remove('dataType')}'"
        }

        // Additional attributes
        if (attrs.params || attrs.jsParams) {
            if (!(attrs?.params instanceof Map)) {
                // tags like remoteField don't deliver a map
                out << ",data:${attrs.remove('params')}"
            } else {
                out << ",data:{"

                boolean hasParams = false

                if (attrs?.params instanceof Map) {
                    hasParams = true
                    out << attrs.remove('params').collect { k, v ->
                        "\'" +
                                "${k}".encodeAsJavaScript() +
                                "\': \'" +
                                "${v}".encodeAsJavaScript() +
                                "\'"
                    }.join(",")
                }

                if (attrs?.jsParams instanceof Map) {
                    if (hasParams) {
                        out << ","
                    }

                    out << attrs.remove('jsParams').collect { k, v ->
                        "\'" +
                                "${k}".encodeAsJavaScript() +
                                "\': \'" +
                                "${v}".encodeAsJavaScript() +
                                "\'"
                    }.join(",")
                }

                out << "}"
            }
        }

        // build url
        def url = attrs.url ? taglib.createLink(attrs.remove('url')) : taglib.createLink(attrs);
        out << ", url:'${url}'"

        // Add callback
        buildCallback(attrs, out)

        // find all onX callback events
        def callbacks = attrs.findAll { k, v ->
            k ==~ /on(\p{Upper}|\d){1}\w+/
        }

        // remove all onX callback events
        callbacks.each { k, v ->
            attrs.remove(k)
        }

        out << "});"

        // Yeah, I know, return is not needed, but I like it
        return out
    }

    /**
     * Helper method to create callback object
     *
     * @param attrs Attributes to use for the callback
     * @param out Variable to attache the output
     */
    def buildCallback(attrs, out) {
        // TODO check for strlen
        if (out) {
            out << ','
        }

        //*** success
        out << 'success:function(data,textStatus){'

        if (attrs.onLoaded) {
            out << "${attrs.onLoaded};"
        }

        if (attrs.update instanceof Map) {
            if (attrs.update?.success) {
                out << "jQuery('#${attrs.update.success}').html(data);"
            }
        } else if (attrs.update) {
            out << "jQuery('#${attrs.update}').html(data);"
        }

        if (attrs.onSuccess) {
            out << "${attrs.onSuccess};"
        }

        out << '}'

        //*** failure
        out << ',error:function(XMLHttpRequest,textStatus,errorThrown){'

        if (attrs.update instanceof Map) {
            if (attrs.update?.failure) {
                // Applied to GRAILSPLUGINS-1919
                out << "jQuery('#${attrs.update?.failure}').html(XMLHttpRequest.responseText);"
            }
        }

        if (attrs.onFailure) {
            out << "${attrs.onFailure};"
        }

        out << '}'

        if (attrs.onComplete) {
            out << ",complete:function(XMLHttpRequest,textStatus){${attrs.onComplete}}"
        }
    }

    /**
     * Serializes the surrounding form.
     *
     * @param attrs attrs.params to serialize
     */
    def prepareAjaxForm(attrs) {
        // Fix for http://jira.codehaus.org/browse/GRAILSPLUGINS-1865
        if (attrs.forSubmitTag) {
            attrs.params = "jQuery(this).parents('form:first').serialize()".toString()
        }
        else {
            attrs.params = "jQuery(this).serialize()".toString()
        }
    }
}

Register this class as the provider (for AJAX GSP tags) in Bootstrap.groovy

import org.codehaus.groovy.grails.plugins.web.taglib.JavascriptTagLib

class BootStrap {

    def init = { servletContext ->    
        JavascriptTagLib.PROVIDER_MAPPINGS.jquery = JQueryProvider
    }
}

Upvotes: 0

Ricky Martinez
Ricky Martinez

Reputation: 31

This link was very useful and shows what steps you might need to take. https://grails.org/plugin/jquery

Edit: Using the above website I got mine to wrok by doing this:

  1. put this in config.groovy: grails.views.javascript.library = "jquery"
  2. put this ins buildConfig.groovy runtime "org.grails.plugins:jquery:1.11.1"
  3. note(someone suggested another plugin and it actually broke mine)
  4. I didn't need to do anything else (I removed the g:javascript tag completely) and it just worked.

Upvotes: -1

user800014
user800014

Reputation:

Since you're manually setting the JQuery resource, there's no need to set:

<g:javascript library="jquery"/>

Instead, just require your module:

<r:requires module="jquery, jquerymobile"/>

EDIT

Looking at your new info, I think that your issue is with the remoteFunction method. Since it needs to know which javascript library you're using. Try adding <g:setProvider library="jquery"/> to your page.

Upvotes: 2

denov
denov

Reputation: 12688

I just resolved the same error what was caused from a g:remoteLink tag. I found that I need to call twice. Once in the head, and the other in the footer where you should be loading js files from. I also had to add jQuery as a plugin in BuildConfig.groovy

plugins {
    runtime ":jquery:1.8.3"
    runtime ':resources:1.2'
    ...
}

My main.gsp has

  <r:require modules="app, jquery" />
  <g:setProvider library="jquery" />
  <r:layoutResources/>
  <g:layoutHead />

I have g:layoutHead last so jQuery loads before scripts that may need it.

If you are just inline some scripts you may want to look at

If you use this tag to render inline JavaScript code, it is recommended that you use the Resources plugin's tag to produce inline script that is included at the end of the body, or in the head if necessary - rather than inline. For more control use the Resources plugin's tag directly. -

Upvotes: 1

jenk
jenk

Reputation: 1043

try to put

grails.views.javascript.library = "jquery"

into Config.groovy or insert into main layout:

<g:setProvider library="jquery"/>

Upvotes: 0

Related Questions