KendoDropdown placed in fancybox popup = Bad practice? - kendo-ui

There is a problem when I put Kendo Dropdown List info Fancybox - Popup.
For detail:
I have page A :this page contains Kendo Dropdown list (with id = #myDropdown).
I have page B : I put my Fancybox caller here- I mean I use Fancybox to load page A (by ajax)
Everything look well , but I got a problem here:
You know, when I initialize a Dropdown List, Kendo-UI will create an "anchor" Tag for UI-effect purpose.
Ex:
DropdownList has id = #myDropdown
Kendo will create one more Tag with id = #myDropdown-list.
After closing the Fancybox-popup , The "#myDropdown" was removed from DOM, but "#myDropdown-list". It still on the DOM overtime, and it willing to be double after I call the popup again(ofcourse if dont refresh current page).
And The Kendo-DateTimePicker as the same too.
p/s: and so sorry about by english if it was too bad :D. I hope you get my question.
im going to put my "popup" in iframe.But I dont know if it is good when using iframe in this case...

Using IFrame or not is not the cause of the error. I tried with a container and without it to load the fancybox via ajax, but it didn't make a difference.
What I found is sort of a hack, however it solves the problem. Let's suppose we have a code which creates the popup and the popup's content is located in the href 'popupFrame':
$.fancybox({
'href': 'popupFrame',
'type': 'ajax',
beforeClose: removeKendoHelpers
});
The other part is the function which is called before closing the popup:
function removeKendoHelpers() {
$("#myDropdown-list").remove();
}
Of course you can create the removeKendoHelpers as an inline function and if there are more parts to remove then put that code into the removeKendoHelpers function as well.
One interesting remark: in the fancybox API onCleanup and onClosed are listed as options but they do not work, instead use beforeClose or afterClose.
UPDATE:
Actually a lot of problem is solved with calling the kendo widget's destroy() method. It solves the removing problems for the widgets except for one of the three helper divs of the DateTimePicker, so the close looks like the following:
function removeKendoHelpers() {
$("#myDropdown-list").data("kendoDropDownList").destroy();
$("#datetimepicker").data("kendoDateTimePicker").destroy();
}
And to resolve the date time picker's actual problem which is I think a bug in the kendop framework (I will report this and hopefully get some feedback) the last function only needs to be extended with:
$(".k-widget.k-calendar").remove();
OTHER solution:
This one is more crude but works like a charm for me even if the page has multiple kendo controls and even if you open another fancybox from your fancybox.
Wrap the fancybox creation in a function, like:
function openFancyBox() {
$("body").append("<div class='fancybox-marker'></div>");
$.fancybox({
'href': 'popupFrame',
'type': 'ajax',
beforeClose: removeKendoHelpers
});
}
This will create a new div at the very end of the body tag, and the function at the closing of the fancybox uses this:
function removeKendoHelpers() {
$(".fancybox-marker").last().nextAll().remove();
$(".fancybox-marker").last().remove();
}
I hope these solves all your problem!

Related

Could not show content in CKeditor after the second time

In my project, the Ckeditor is part of a webpage, which is coded using GWT. So the interface to CKeditor is using Java.
Whenever the webpage is displayed, the CKeditor will be passed a HTML via setData(), which the CKeditor is supposed to show.
The problem is: CKeditor sometimes won't show the HTML. Its content was just empty, although I am very sure the html had been passed to setData().
I had tried several approaches to solve this problem, but none would work.
My approach
Create a TextArea using DOM.createTextArea()
Call myEditor=CKEDITOR.replace(textArea, config) to initialize the CKeditor
call myEditor.setData(html) to set the content.
It was good and showed the content at the first time.
But after the webpage got hidden and shown again, I called myEditor.setData(html2) to show another html, but this time the CKeditor showed nothing.
First solution (did not work)
I changed the code to call myEditor.destroy() before the webpage was hidden, and call CKEDITOR.replace(textArea, config) again when the webpage was visible again, after that I called myEditor.setData(newHtml).
This time it worked in IE and FF, but not in Chrome and Edge, it kept showing the content of the first load time, instead of showing the new HTML.
Second solution (did not work)
I changed it to call CKEDITOR.inline(textArea, config) instead of CKEDITOR.replace(textArea, config) when the webpage was visible again, while the destroy() and setData() was still called in the same order. This time the CKeditor again didn't show anything from the second time.
Last attempt
My last approach was to not calling destroy(), but creating a new TextArea each time before showing CKeditor, and called CKEDITOR.replace(textArea, config) and setData(html). This seems to work well, but occasionally the CKeditor still showed empty content.
Could anyone please help me to solve this problem?
I am using CKeditor 4.5.8.
Finally I figured out the solution:
Before hiding the ckeditor, call editor.destroy(true), and delete editor. (Before this, I only called editor.destroy() [note: no 'true'], which didn't work well).
Here is the code:
if (editor) {
editor.destroy(true);
delete editor;
}
Use this java script code that is very simple and effective.Note editor1 is my textarea id
<script>
$(function () {
CKEDITOR.timestamp= new Date();
CKEDITOR.replace('editor1');
});
</script>
second way ! In controller ,when your query is fetch data from database then use this code after .success(function().
$http.get(url).success(function(){
CKEDITOR.replace('editor1');
});

The view area of ckEditor sometimes shows empty at the start

I am using the following directive to create a ckEditor view. There are other lines to the directive to save the data but these are not included as saving always works for me.
app.directive('ckEditor', [function () {
return {
require: '?ngModel',
link: function ($scope, elm, attr, ngModel) {
var ck = ck = CKEDITOR.replace(elm[0]);
ngModel.$render = function (value) {
ck.setData(ngModel.$modelValue);
setTimeout(function () {
ck.setData(ngModel.$modelValue);
}, 1000);
}; }
};
}])
The window appears but almost always the first time around it is empty. Then after clicking the [SOURCE] button to show the source and clicking it again the window is populated with data.
I'm very sure that the ck.setData works as I tried a ck.getData and then logged the output to the console. However it seems like ck.setData does not make the data visible at the start.
Is there some way to force the view window contents to appear?
You can call render on the model at any time and it will simply do whatever you've told it to do. In your case, calling ngModel.$render() will grab the $modelValue and pass it to ck.setData(). Angular will automatically call $render whenever it needs to during its digest cycle (i.e. whenever it notices that the model has been updated). However, I have noticed that there are times when Angular doesn't update properly, especially in instances where the $modelValue is set prior to the directive being compiled.
So, you can simply call ngModel.$render() when your modal object is set. The only problem with that is you have to have access to the ngModel object to do that, which you don't have in your controller. My suggestion would be to do the following:
In your controller:
$scope.editRow = function (row, entityType) {
$scope.modal.data = row;
$scope.modal.visible = true;
...
...
// trigger event after $scope.modal is set
$scope.$emit('modalObjectSet', $scope.modal); //passing $scope.modal is optional
}
In your directive:
ngModel.$render = function (value) {
ck.setData(ngModel.$modelValue);
};
scope.$on('modalObjectSet', function(e, modalData){
// force a call to render
ngModel.$render();
});
Its not a particularly clean solution, but it should allow you to call $render whenever you need to. I hope that helps.
UPDATE: (after your update)
I wasn't aware that your controllers were nested. This can get really icky in Angular, but I'll try to provide a few possible solutions (given that I'm not able to see all your code and project layout). Scope events (as noted here) are specific to the nesting of the scope and only emit events to child scopes. Because of that, I would suggest trying one of the three following solutions (listed in order of my personal preference):
1) Reorganize your code to have a cleaner layout (less nesting of controllers) so that your scopes are direct decendants (rather than sibling controllers).
2) I'm going to assume that 1) wasn't possible. Next I would try to use the $scope.$broadcast() function. The specs for that are listed here as well. The difference between $emit and $broadcast is that $emit only sends event to child $scopes, while $broadcast will send events to both parent and child scopes.
3) Forget using $scope events in angular and just use generic javascript events (using a framework such as jQuery or even just roll your own as in the example here)
There's a fairly simple answer to the question. I checked the DOM and found out the data was getting loaded in fact all of the time. However it was not displaying in the Chrome browser. So the problem is more of a display issue with ckEditor. Strange solution seems to be to do a resize of the ckEditor window which then makes the text visible.
This is a strange issue with ckeditor when your ckeditor is hidden by default. Trying to show the editor has a 30% chance of the editor being uneditable and the editor data is cleared. If you are trying to hide/show your editor, use a css trick like position:absolute;left-9999px; to hide the editor and just return it back by css. This way, the ckeditor is not being removed in the DOM but is just positioned elsewhere.
Use this java script code that is very simple and effective.Note editor1 is my textarea id
<script>
$(function () {
CKEDITOR.timestamp= new Date();
CKEDITOR.replace('editor1');
});
</script>
Second way In controller ,when your query is fetch data from database then use th
is code after .success(function().
$http.get(url).success(function(){
CKEDITOR.replace('editor1');
});
I know, that this thread is dead for a year, but I got the same problem and I found another (still ugly) solution to this problem:
instance.setData(html, function(){
instance.setData(html);
});

How to close fancybox within an ajax popup with another version of jquery loaded?

I am having an issue closing a fancybox popup when jquery is included within the popup page (i'm using AJAX and including an external php page within the popup). The fancybox is setup as follows:
$(".various3").fancybox({
'type' : 'ajax',
'titlePosition' : 'inside',
'transitionIn' : 'none',
'transitionOut' : 'none',
'ajax' : {
type : 'GET'
}
});
The popup has a 'Cancel' button to allow users to close the popup (using jQuery.fancybox.close();). I have to include jquery within the popup page to allow some other functionality to work and this prevents the jQuery.fancybox.close(); from working. If i remove jquery from the popup page then it works fine, however I cannot work out how to reference the instance of jquery on the main page (i have tried parent in case, although i wouldn't have thought this should work as it's a div and indeed it didn't). I have tried using:
var localjquery = jQuery.noConflict(true);
within the popup page and this allows me to use jQuery.fancybox.close(); to close the popup successfully however this prevents the use of $ to reference jquery which is needed for other plugins on this page that i can't edit. If I add
var mainjquery = jQuery.noConflict();
after the first instance of jquery on the main page then this obviously works fine and i can refer to it as mainjquery on the parent, but if then try
mainjquery.fancybox.close();
on the popup it says mainjquery is undefined.
I suspect it's a problem due to a combination of multiple jquery instances and loading a completely separate page via ajax into a div (rather than using an iframe etc whereby i could then use parent. or similar). If anyone could shed any light on how I could reference the mainjquery reference from the child popup, or a better way I can close the fancybox then that would be greatly appreciated.
Thanks so much!
Dave
The best thing to do is test to see if it is an ajax request, and if so don't include the jquery (or any other scripts you already have for that matter).
Here's a sample of code I use on my php pages for doing both ajax and regular page requests.
define('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
....
if(!IS_AJAX)
{
//echo your header with scripts
echo $header;
}
//else just echo the contents of the page body
edit:
If you need to add things to the head tag, you should be using an iframe instead of an ajax type for the fancybox.

Loading forms with .load kills the submit button in Firefox

I am currently loading several forms into a webpage with:
$(document).ready(function () {
$('#content').load('php_script.php', function() {
$(this).find('#someForm').ajaxForm(function() {
alert('Success!');
});
$(this).find('.someOtherForm').ajaxForm(function() {
alert('Success!');
});
});
});
This works in Chrome, Chromium and IE who loads the forms and everything works as it should (Clicking submit sends a request to the php-script defined in the form's action, which adds stuff to a db, and shows the alert dialog). In Firefox (v10.0.2) this code loads the forms into the DOM and displays them, but when clicking submit on any of the forms nothing happens.
At first I suspected ajaxForm, but changing the above code to:
$(document).ready(function () {
$('#content').load('php_script.php');
});
yields almost the same result, the difference being that the user is sent to the script defined as the action (Except for Firefox, where nothing happens).
How do I make Firefox not kill the submit button?
I solved it, bad HTML from my side:
<table><form ...>
<tr>...</tr>
</form></table>
Instead it should look like:
<form ...><table>
<tr>...</tr>
</table></form>
The validator did not catch this since it was loaded via jQuery (and I forgot to validate the page serving the forms), and Firefox buggered out.
The code above looks ok to me...
Have you had a look in firebug if there are any errors? Maybe there is a conflicting Id or something.
Maybe the form isnt completely loaded into the dom yet, might be worth giving live binding a try
Found this in the docs:
...jQuery uses the browser's .innerHTML property to parse the retrieved document and insert it into the current document. During this process, browsers often filter elements from the document such as , , or elements. As a result, the elements retrieved by .load() may not be exactly the same as if the document were retrieved directly by the browser...
If you inspect the form is it the same as in other browsers?

loading colorbox from within AJAX content

Firstly I am very new to all forms of javascript, particularly anything remotely AJAX. That said, over the course of the last day I have managed to code a script that dynamically refreshes a single div and replaces it with the contents of a div on another page.
The problem however is that several of my other scripts do not work in the ajax refreshed content. The most important of which being "colorbox".
I have spent several hours this evening researching this and am seeing lot's of stuff regarding .load, .live... updating the DOM on refresh etc...etc... But to be quite honest most of it is going over my head currently and I wouldn't know where to begin in terms of integrating it with the code I currently have.
My Ajax refresh code is as follows (My apologies if I haven't used best practice, it was my first attempt):-
$(function() {
$(".artist li.artist").removeClass("artist").addClass("current_page_item");
$("#rightcolumnwrapper").append("<img src='http://www.mywebsite.com/wp-content/images/ajax-loader.gif' id='ajax-loader' style='position:absolute;top:400px;left:190px;right:0px;margin-left:auto;margin-right:auto;width:100px;' />");
var $rightcolumn = $("#rightcolumn"),
siteURL = "http://" + top.location.host.toString(),
hash = window.location.hash,
$ajaxSpinner = $("#ajax-loader"),
$el, $allLinks = $("a");
$ajaxSpinner.hide();
$('a:urlInternal').live('click', function(e) {
$el = $(this);
if ((!$el.hasClass("comment-reply-link")) && ($el.attr("id") != 'cancel-comment-reply-link')) {
var path = $(this).attr('href').replace(siteURL, '');
$.address.value(path);
$(".current_page_item").removeClass("current_page_item");
$allLinks.removeClass("current_link");
$el.addClass("current_link").parent().addClass("current_page_item");
return false;
}
e.preventDefault();
});
$.address.change(function(event) {
$ajaxSpinner.fadeIn();
$rightcolumn.animate({ opacity: "0.1" })
.load(siteURL + event.value + ' #rightcolumn', function() {
$ajaxSpinner.fadeOut();
$rightcolumn.animate({ opacity: "1" });
});
});});
I was hoping someone might be kind enough to show me the sort of modifications I would need to make to the above code in order to have the colorbox load when the contents of #rightcolumn have been refreshed.
There is also a second part to this question. My links to the pictures themselves are now also being effected by the hashtag due to the above code which will in turn prevent the images themselves from loading correctly in the colorbox I should imagine. How can I prevent these images from being effected and just have them keep the standard URL. I only want the above code to effect my internal navigation links if at all possible.
Many thanks guys. I look forward to your replies.
That's a lot of code to review so I'll focus first on the conceptual side of things. Maybe that you will give you some clues...
It sounds like when you load content via Ajax the DOM is changed. No worries, that's kind of what we expect. However, scripts loaded before the Ajax calls may have difficulty if they are bound to elements that weren't there at page load time or are no longer there.
JQuery's live function is one solution to that. Instead of binding to a specific element (or collection of elements) at particular point in time, live lets you specify a binding to an element (or collection) of elements without regard to when they show up in the DOM (if ever).
ColorBox, however, in its default "vanilla" use abstracts that all away and, I believe, uses classic DOM binding - meaning the elements must be present at bind time. (Since you don't show your call to ColorBox I can't see how your using it.)
You may want to consider re-initalizing ColorBox after each content load by Ajax to be certain the binding happens the way you need it to.
Use $('selector').delegate() it watches the DOM of 'selector' and .live() is deprecated.
Use this to watch your elements AND fire the colorbox initilization. This way the colorbox is not dependent on the DOM element, but the other way around.
$("body").delegate("a[rel='lightbox']", "click", function (event) {
event.preventDefault();
$.colorbox({href: $(this).attr("href"),
transition: "fade",
innerHeight: '515px',
innerWidth: '579px',
overlayClose: true,
iframe: true,
opacity: 0.3});});
This should basically solve your problem and is cross browser tested.
The a[rel='lightbox'] in the delegate closure is the reference to what ever link you're clicking to fire the colorbox, whether it has been loaded with the initial DOM or with an AJAX request and has been added to the DOM in a live fashion. ie: any tag like this:
<a rel='lightbox' href="http://some.website.com">Launch Colorbox</a>

Resources