Strange errors when including Yii view in IFRAME.

I have many views in my application and up until now - no problems at all with all of them.

Recently I wanted to display one of them inside IFRAME, that is a part of CJuiDialog, displayed after button click in another view.

Everything works perfectly in Firefox 8 and Chrome 15. But when I display mother view (the one containing button and IFRAME) in Internet Explorer 9, I’m getting a bunch of very strange errors:


Error: Missing definition of „Object”

Line: 21

Char: 105

Code: 0

URI: [app_path]/assets/7126e48d/jquery.min.js


Error: Missing definition of „jQuery”

Line: 80

Char: 2

Code: 0

URI: [app_path]/assets/7126e48d/jquery.ba-bbq.js


Error: Missing definition of „jQuery”

Line: 10

Char: 2

Code: 0

URI: [app_path]/assets/7126e48d/jui/js/jquery-ui.min.js


Error: Missing definition of „jQuery”

Line: 67

Char: 1

Code: 0

URI: [app_path]/assets/eed4395f/ajaxtooltip.js


Error: Missing definition of „jQuery”

Line: 11

Char: 3

Code: 0

URI: [app_path]/assets/760c1158/gridview/jquery.yiigridview.js


Error: Missing definition of „jQuery”

Line: 10

Char: 2

Code: 0

URI: [app_path]/assets/7126e48d/jui/js/jquery-ui.min.js


Error: Missing definition of „jQuery”

Line: 1

Char: 1

Code: 0

URI: [app_path]/assets/7126e48d/jui/js/jquery-ui-i18n.min.js


Error: Missing definition of „jQuery”

Line: 222

Char: 1

Code: 0

URI: [app_path]/pacjenci/index.html?type=rejestracja

The last one ("[app_path]/pacjenci/index.html?type=rejestracja") is a view that I want to display in IFRAME.

Even though these errors are reported, both mother view and IFRAME’s view are perfectly rendered and working.

I must underline that this happens only in newest IE and only if both views are displayed in the same time, one inside another one. Because each of them displayed as separate view (rendered by proper actions) are 100% working perfectly, without any errors, in all browsers, in which I’ve tested them.

those are JS errors… not sure why IE fires those errors… but you can try to prevent them by loading all the required javascript files in the parent view… and disabling them for the juidialog/iframe

Note: Post re-edited and previous contents changed, to avoid unnecessary mess in the text.

I also get no idea, why IE shows them?

That doesn’t seems to be that easy. Errors are being thrown by IE, even if layout used to render view in iframe does not contains any direct scripts declaration - i.e. for the scripts registered internally by CGridView. Do we have an easy / any way to prevent CGridView from auto-registering necessary scripts?

And also a word about interaction between DOM objects in parent view and iframe ones.

I didn’t find any idea or solution on how to set values of parent view from code inside inner view - i.e. click on grid view in iframe would set a field’s value in parent view.

But for different way – getting value from iframe view, by code put into parent view, this seems to be easy. I’ve tried example from jQuery’s docs – using .contents():


alert($("#pacjenci-iframe").contents().find("Pacjenci_PESL").val())

It seems to be working fine.

You should only notice, that if you inject code for this kind of manipulation directly into buttons array, this might fail in many situations, with browser (tested in IE, FF and Chrome) reporting an error saying "h.apply is not a function in: assets/7126e48d/jui/js/jquery-ui.min.js line: 337".

As I wrote in a comment to CJuiDialog, a simple workaround for this problem, is to move necessary code to a separate JS function and only put call to that function directly into CJuiDialog->options->buttons array.

So, this one is solved. There’s only one thing left to answer – how to prevent CGridView and others from auto-registering jQuery scripts, when inner view is rendered using render(), what causes IE to throw those nasty errors. I found out, that using renderPartial() does solves problem, but then grid view and other elements are looking ugly, since they don’t share styles declared or linked into parent view.

Maybe solution would be to render page using renderPartial() only and inject whole styles, as good as whole jQuery minified directly into view, using <style> and <scripts> tags? I did something like that, when in some specific internal solution (a small HTML piece run inside Delphi program) I had to have styles and jQuery in a HTML code stored directly in a database field.

I never used an iframe… as I don’t like them…

An iframe is a separate page… so even if it looks as part of the current page… in fact those are two pages… it’s like you would have two pages in two separate tabs and now you want on one page to display the value that is on the other page…

check your logic… and see if you can do it without an iframe… you can try with a jQuery UI dialog - http://www.yiiframework.com/doc/api/1.1/CJuiDialog

Problems partially solved - see my re-edited answer above.

The only thing that left, is how to preven CGridView, from auto-registering jQuery scripts, when rendered using render() (does not register them automatically, when rendered using [i]renderPartial/i.

I’m also not to big fan of IFRAMES. Actually those (inline ones) are the only one accepted by my, as I dropped normal frames idea long time ago. But, if you don’t like IFRAME’s then how you would solve, using different approach, a problem of making lookup window in HTML page?

I.e. you have order edit form, and one of fields in this form is a customer name (and/or ID) and you have to design a window (jQuery UI dialog) where user will see a list of customers along with ability of sorting it, filtering it and with pagination mechanism.

Of course, you can design such dialog, piece by piece, using fields, buttons and AJAX calls. But, is it worth doing so, if you already have a customer-list view ready and used in another part of an application?

I think that using IFRAME is the fastest way in this particular situation. And it can also be considered as good practice, since you’re reusing already wrote code, instead of writing new one.

Problem with preventing auto-registration of script files I’ve solved introducing my own version of CController:render() that does not processes output:


public function renderLookup($view, $data = null, $return = false, $layoutFile = '//layouts/lookup')

{

    	$output = $this->renderPartial($view, $data, true);

    	$layoutFile = $this->getLayoutFile($layoutFile);


    	if($layoutFile !== FALSE) $output = $this->renderFile($layoutFile, array('content'=>$output), TRUE);


    	if($return) return $output; else echo($output);

}

For the reasons discussed in this article I strongly advice to modify original CController:render() function, so processing output would also be parametrized, just like in CController:renderPartial().

Problem with missing CSS styles I solved by referencing them in a special layout file, prepared strictly for rendering view in IFRAME and using above function to render view using this layout. I only have to copy styles and graphic files from gridview folder inside framework, to my own styles folder.

Problem with missing jQuery I dropped, since in this particular view I need it only for four on-click bindings, so I can achieve the same with inline JavaScript referencing. However, people using jQuery much more in IFRAMES will probably have to throw it’s minified code directly into view file, as I proposed, to avoid those idiotic error messages in Internet Explorer.

Nope, at all! It seems that Internet Explorer isn’t simply able to handle having two copies of jQuery – one in parent view and second in inline view, in IFRAME. No matter, if you load second one by referencing via path in the head or if you inject it’s whole code as regular script, using <script> and </script> tags.

The most irritating thing is, that even though errors are being shown, jQuery inside IFRAME is perfectly working! You can bind functions, use simple animations etc.

I’ve double checked that, it IFRAME view, is not using parent view’s jQuery, by disabling second copy (that caused errors to appears). Effect? No error messages and no jQuery code working.

I simply can’t find any comment to situation, that browser can state, something is undefined, bloat user with lot of errors and then continue working, like nothing would happened, perfectly using that undefined code.

So, if you want to inline view inside another view, using IFRAME, you have two options: completely resign from using jQuery inside that inline view or… completely resign from users using Internet Explorer…

EDIT: The problem seems to by caused by any additional library loaded with onLoad event in the contents of inner (IFRAME) view. Not just jQuery. In the process of working-around above discussed problem, I’ve used a function that uses JS RegExp library. Everything was fine until function was fired by a button click. After moving it to [i]onLoad of inner page, again nasty errors of undefined objects or elements started to appear.

And again, after [/i]clicking-out those error messages, it turned out that everything is fine, function is working and is using regular expressions without any problems.