Reputation: 587
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
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
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:
Upvotes: -1
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
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
Reputation: 1043
try to put
grails.views.javascript.library = "jquery"
into Config.groovy or insert into main layout:
<g:setProvider library="jquery"/>
Upvotes: 0