2011-10-04 13 views
5

Estoy lidiando con una situación en la que debo vincular eventos jQuery a una página para manejar actualizaciones de UI que se están generando a través de JSF. Por desgracia, JSF es una mierda y tiene eventos onclick en todo, lo que evita cualquier trabajo de jQuery.Tratando con `return false` cuando se usa` eval`in JavaScript

Gracias a la buena gente aquí en la SO, he encontrado una solución para eso:

mixing my jQuery click events with existing object's onclick attribute

La lógica es:

  • al cargar la página, agarrar todos los onclick atributos y almacenarlos en una variable.
  • se unen mis eventos jQuery
  • después de mis propios eventos de jQuery, que puede entonces eval el original onclick: eval(onclickValueVariable)

Esto funcionó encontrar en todas mis pruebas evento onclick maniquí.

Pero luego falló en esa página en vivo JSF. La cuestión es que todos los fines de la onclick con un 'return false' que conduce a este error:

return not in function 

Por ejemplo:

<div class="uglyJSFcreatedTag" onclick="console.log('hey');return false"> 

Y el jQuery que dispararla:

var $jsfTag = $('.uglyJSFcreatedTag'); 
var cacheOnclick = $jsfTag.attr(onclick); 
$jsfTag.removeAttr('onclick'); 

...bunch of logic here to decide if the inline onclick should fire and, if so... 

eval(cacheOnclick) 

El problema es el return false. Parece que no se puede devolver nada al disparar una evaluación.

¿Existe una solución para esto? Me imagino que podría tomar el valor como una cadena y hacer una cadena de análisis para eliminar todo devolver falso, luego llamar eso desde el script en sí. Pero eso suena un poco desordenado. ¿Hay una solución más elegante?

Si no, ¿qué enunciados JS concretos debería buscar para filtrar antes de llamar al eval?

+0

Honestamente no tengo ni idea de lo que estás tratando de hacer, pero creo que puedo ayudarte. – mowwwalker

+0

¿Por qué no agregas a todos tus oyentes de la misma manera? es decir, todos usan JSF o todos usan jQuery. – RobG

+0

No estoy escribiendo el JSF. Y no veo cómo agregar más lógica UI a través del camino hacia atrás JSF sería un paso en la dirección correcta. Mi trabajo es hacer que la interfaz de usuario funcione lo mejor que pueda, dado lo que el equipo de JSF me ofrece. Se remonta a los días de trabajo de SharePoint ... piratea sobre hacks. ;) –

Respuesta

6

dos opciones:

1. Uso de su enfoque actual, simplemente envuelven la cadena onclick con una función antes de que eval. Almacene el resultado y llámelo como una función. Asegúrate de que llamar con el contexto apropiado this:

var f = eval("(function(){ "+cacheOnclick+"})"); 
f.call($jsfTag[0]); 

Nota: el paréntesis () alrededor de la declaración de la función, son necesarios dentro de la eval. Esto hace que la declaración sea una expresión (sintácticamente hablando), lo que hace que sea legal en la evaluación.

2. en lugar de agarrar el atributo onclick, tome la función real del elemento dom. Además, a menos que hay que hacer algo especial con la función de controlador JSF de su código, sugeriría que usted acaba de añadir la función de JSF como un manejador de jQuery clic directamente, en lugar de llamar explícitamente a partir de su código:

var $jsfTag = $('.uglyJSFcreatedTag'); 
$jsfTag.bind('click', $jsfTag[0].onclick); 
$jsfTag.removeAttr('onclick'); 

Personalmente, preferiría el enfoque n.º 2, pero cualquiera de los dos debería funcionar.


actualización: He aquí una explicación adicional litte para la Opción # 2:

var $jsfTag = $('.uglyJSFcreatedTag'); 

Eso es de su ejemplo - que estamos usando jQuery para recuperar un conjunto que contiene todos los elementos con el nombre de clase ' uglyJSFcreatedTag '.

$jsfTag.bind('click', $jsfTag[0].onclick); 

Esto obtiene el primer elemento del conjunto ($jsfTag[0]), y obtiene la propiedad de ese objeto onclick elemento. .onclick es una propiedad de javascript que contiene una referencia a la función compilada que el navegador generó a partir del contenido de cadena del atributo "onclick". Ahora, dado que tenemos la función de controlador, podemos vincularla directamente al evento de clic de jquery, usando jquery bind() function.

$jsfTag.removeAttr('onclick'); 

Finalmente, eliminamos el atributo. Esto está bien, porque ya hemos enlazado la función a través de jquery. Si no lo eliminamos del clic en "estilo antiguo", se lo llamará dos veces.

Nota: Es posible que haya notado que el código anterior solo funciona en el primer elemento del conjunto seleccionado. Para el caso muy probable de que su conjunto contenga múltiples elementos, querrá recorrer el conjunto y manejar cada elemento por separado. He aquí cómo usted haría lo siguiente:

var $jsfTag = $('.uglyJSFcreatedTag'); 
$jsfTag.each(function(idx, element) { 
    $(element).bind('click', element.onclick).removeAttr("onclick"); 
}); 

Si desea omitir el controlador JSF para ciertos elementos, a continuación, insertar la lógica dentro de la "cada bucle" para probar esto, y pasa la llamada a unirse en consecuencia.


Si debe continuar llamando al controlador JSF desde dentro de su controlador de clic, a continuación, al menos considerar el uso de element.onclick en lugar de $(element).attr('onclick'). Este último requiere evaluación, mientras que el primero no.

+0

El primero parece tener sentido para mí. Sin embargo, eso da un error diferente: 'function statement requires a name'. No estoy seguro de que la segunda opción funcione para nosotros, aunque tengo que admitir que no estoy siguiendo completamente lo que está haciendo el segundo.Debo mencionar que no siempre queremos que onclick eval (tenemos alguna lógica que decide si se activa o no). –

+0

# 2 es preferido, el # 1 es simplemente feo. – RobG

+0

No debería obtener ese error si incluyó el paréntesis alrededor de la función. Agregué esos (y la nota correspondiente) en una edición inmediatamente después de hacer la publicación inicial, así que tal vez los extrañaste. Dicho esto, el # 2 realmente es un enfoque mucho más limpio, y no implica el uso de 'eval()' (que generalmente debes evitar a menos que realmente lo necesites). – Lee

4

Creo que envolver el código en una función anónima e invocarlo de inmediato debería ser más fácil que filtrar declaraciones de devolución.

evalCode = "function() {" + evalCode + "}()"; 
+0

Cerrar, pero cuando se llama al manejador inline (anteriormente), su * this * palabra clave no hará referencia al elemento, por lo que se trata de un problema más. – RobG

+0

Buen punto @RobG: la sugerencia de Lee 1. debería manejar esto. –

Cuestiones relacionadas