3

I use jQuery widget factory (jQuery widgets) for my js widgets.

$.widget('cool.someWidget', {
     options: {
         onSomething: null
     }
     // other js code
});

Normally to run the widget from js you write

$(selector).someWidget({
    onSomething: function() { ..... }
});

In Yii I use CJSON::encode to compile all the initialization properties which include the onSomething event.

echo CJSON::encode(array(
    'onSomething' => 'function() {....}',
));

However due to the conversion (CJSON), it converts the function() {...} to a string so in the document it is written the following

$(selector).someWidget({
    onSomething: "function() { .... }"
});

because the onSomething is actually a string when I call the this._trigger('onSomething') it doesn't run the code.

This problem I have only when I "generate" the view and not with Ajax requests (which I handle differently in the system). Is there some "normal" way of making Yii actually write in the document the function withought the quotes?

1

4 Answers 4

3

There is actually a build in way to prevent the encode function from wrapping function declaration with quotes , you should add js: before your function declaration

CJavaScript::enocde(array(
   'prop'=>'value',
   'callback' => 'js:function(){}'
))
Sign up to request clarification or add additional context in comments.

Comments

1

IMHO the premise of the question is flawed, and it would be much better if you side-stepped this issue entirely.

What is the problem here? You cannot supply JavaScript code as a PHP string.

Why do you want to do that? I don't believe a compelling reason exists. JavaScript code should be written as JavaScript code; writing it as a string is simply worse.

It is quite probable that you wanted to pass a bunch of options available to you as PHP variables to the plugin, and in the excitement it seemed a good idea to pass all the options (including those that are functions) in the same manner.

But there is another way, courtesy of $.extend: use CJSON::encode for all the scalars (strings, numbers) and switch back to pure JavaScript for the callbacks.

$(selector).someWidget($.extend(
    <?php echo CJSON::encode(array(/* no functions here, just scalars */));?>,
    { // and now, back in JavaScript-land, code follows:
        onSomething: function() { ..... }
    }
));

4 Comments

It feels fare to be able to do that. Yii has the CJSON so it correctly encodes all strings to strings. But sometimes all you need to do "bind" plugins in a chain is to run a function of a plugin on the event of another. As to why I want to do that in PHP (Yii)? So my widgets can correctly write everything and not suffer from the overhead of selecting and binding.
This should be the answer, imho
@Jon: We're talking about widgets here. Reusable pieces of code, Yii developers can insert into their applications. How would you like to pass Javascript code in this case? As you can see, a compelling reason does exist. And, now what? You throw you hat in, and when defeated with a good quality argument, you're not even willing to respond? How polite...
@trejder: The astute reader will notice that while jQuery widgets are specifically referenced in the question, Yii widgets are not. There's a reference to Yii of course but nothing in the question talks about Yii widgets. There is even nothing in the comment above referring to Yii widgets. There's also nothing like that in the OP's "final solution" below. So before going around accusing people, perhaps checking your assumptions would be in order.
0

I wrote the following function which does exactly what I wanted. Still if there's some native Yii solution I'd really love to know it.

public function encodeOpts($data, $jsCode = null) {
    $rVal = CJSON::encode($data);

    if ($jsCode == null)
        return $rVal;

    foreach($jsCode as $key => $code) {
        $codeEntries[] = "\"{$key}\": {$code}";
    }

    return substr_replace($rVal, ', ' . implode(', ', $codeEntries), -1) . '}';
}

Comments

0

I solved like this:

if ($this->user_options !== null && is_array($this->user_options))
{
    $reqs = CJavaScript::encode(
        array_merge(
            $this->user_options,
            array(
                // adding a default callback to options 
                'onLoad' => 'js: function() {$("#info").text("Hi")}'
                )
            )
        );
}

NOTE: js: only works for CJavaScript not forCJSON

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.