jQWidgets Forums
jQuery UI Widgets › Forums › Layouts › Layout and Docking Layout › saveLayout, loadLayout weird behavior
This topic contains 26 replies, has 2 voices, and was last updated by Crisium 3 years, 10 months ago.
-
Author
-
There is something not right, either a bug or I am missing something.
Saving the layout saves floatGroups that have been closed, so when you load again it shows panels that have been closed. Do I need to destroy them or remove them from the layout when the use clicks the close icon?
Also, I have already reported this with no answer. When you load the floatGroup panel, the panel is loaded twice.
Things keep getting weirder.
If I call loadLayout twice then it works correctly.
(<any>$(‘#jqxDockingLayout’)).jqxDockingLayout(‘loadLayout’, JSON.parse(json_layout));
(<any>$(‘#jqxDockingLayout’)).jqxDockingLayout(‘loadLayout’, JSON.parse(json_layout));if I call it only once my floatGroup which has only one item in it shows up twice!
I cannot figure this out with the minimized library, I would need the source code to debug it.
Hi Crisium,
Thank you for contacting us!
Given the information that you provided its not clear what environment you use(looking at the small piece of code you use Typescript) but when I tested the loadLayout methods with Typescript and didn’t reproduce the issue that you do.
I strongly advise you to create a code example for us that reproduces the issue in order to give you solution about it!
However in the meantime you can also check out this forum topic which maybe relates to similar issue:
https://www.jqwidgets.com/community/topic/unable-to-convert-savelayout-method-returned-result-to-string/
and also this one:
https://www.jqwidgets.com/community/topic/modifying-jqxdockinglayout-content/Please, don’t hesitate to contact us if you have any questions!
Best Regards,
Yavor Dashev
jQWidgets team
https://www.jqwidgets.comHi Yavor,
I understand you need a test setup and I actually did create a test setup using npm that can be installed. The only problem is that works in the test setup. I don’t know why it works there and not in the main project, since they are basically the same for the exception the test setup up doesn’t import other local libraries (which should not influence the results).
I am confused why the error shows up in the main projects and why it can be resolved by loading it twice?!
I am using npm, typescript which means I use createInstance for the docking layout. This does have other weirdness besides the bug reported here, for example: saveLayout and loadLayout do not exist on the instance created for the docklayout. I have to do a jquery on a selector and call the method by a string supplied (this is not correct if one uses createInstance).
I wish there was a way to let you test it without having the full project (which is big and would have to be cleaned for hardcoded development information about the server).
The way I would test it if I had the source was to hook into the method that creates the floating dialog and see where it is getting the second instancing from?
Hi Crisium,
Thank you for contacting us, again!
Yes, having a example which reproduces the issue is best for finding a solution for the current issue and the behavior reported when using other libraries should not be a problem or a conflict with our jqWidgets library.
However the problem could related to the way you select the component maybe you can try using
@ViewChild
and I also will share with you a working code example for Angular:
// in you app.component.ts fileimport { Component, ViewChild, AfterViewInit , ViewEncapsulation} from '@angular/core'; import { jqxDockingLayoutComponent } from 'jqwidgets-ng/jqxdockinglayout'; import { jqxButtonComponent } from 'jqwidgets-ng/jqxbuttons'; @Component({ selector: 'app-root', templateUrl: './app.component.html', }) export class AppComponent implements AfterViewInit { @ViewChild('myDockingLayout', { static: false }) myDockingLayout: jqxDockingLayoutComponent; @ViewChild('loadLayoutButton', { static: false }) loadLayoutButton: jqxButtonComponent; savedLayout: any; layout: any[] = this.generateLayout(); generateLayout(): any[] { let layout = [ { type: 'layoutGroup', orientation: 'horizontal', items: [{ type: 'autoHideGroup', alignment: 'left', width: 80, unpinnedWidth: 200, items: [{ type: 'layoutPanel', title: 'Toolbox', contentContainer: 'ToolboxPanel' }, { type: 'layoutPanel', title: 'Help', contentContainer: 'HelpPanel' }] }, { type: 'layoutGroup', orientation: 'vertical', width: 500, items: [{ type: 'documentGroup', height: 400, minHeight: 200, items: [{ type: 'documentPanel', title: 'Document 1', contentContainer: 'Document1Panel' }, { type: 'documentPanel', title: 'Document 2', contentContainer: 'Document2Panel' }] }, { type: 'tabbedGroup', height: 200, pinnedHeight: 30, items: [{ type: 'layoutPanel', title: 'Error List', contentContainer: 'ErrorListPanel' }] }] }, { type: 'tabbedGroup', width: 220, minWidth: 200, items: [ { type: 'layoutPanel', title: 'Solution Explorer', contentContainer: 'SolutionExplorerPanel', initContent: () => { // initialize a jqxTree inside the Solution Explorer Panel let source = [{ icon: './../../../images/earth.png', label: 'Project', expanded: true, items: [ { icon: './../../../images/folder.png', label: 'css', expanded: true, items: [{ icon: './../../../images/nav1.png', label: 'jqx.base.css' }, { icon: './../../../images/nav1.png', label: 'jqx.energyblue.css' }, { icon: './../../../images/nav1.png', label: 'jqx.orange.css' }] }, { icon: './../../../images/folder.png', label: 'scripts', items: [{ icon: './../../../images/nav1.png', label: 'jqxcore.js' }, { icon: './../../../images/nav1.png', label: 'jqxdata.js' }, { icon: './../../../images/nav1.png', label: 'jqxgrid.js' }] }, { icon: './../../../images/nav1.png', label: 'index.htm' }] }]; jqwidgets.createInstance('#treeContainer', 'jqxTree', { width: '100%', height: '99%', source: source }) } }, { type: 'layoutPanel', title: 'Properties', contentContainer: 'PropertiesPanel' }] }] }, { type: 'floatGroup', width: 500, height: 300, position: { x: 350, y: 250 }, items: [{ type: 'layoutPanel', title: 'Output', contentContainer: 'OutputPanel', selected: true }] }]; return layout; } saveBtnOnClick(): void { this.savedLayout = this.myDockingLayout.saveLayout(); console.log(this.savedLayout); this.loadLayoutButton.disabled(false); } loadBtnOnClick(): void { this.myDockingLayout.loadLayout(this.savedLayout); console.log(this.savedLayout); this.loadLayoutButton.disabled(true); } ngAfterViewInit():void { } }
Let me know if using
@ViewChild
has worked for you in the mean time I will additionally will discuss it with my colleagues and will try to reproduce the issue that you do.Please, don’t hesitate to contact us if you have any questions!
Best Regards,
Yavor Dashev
jQWidgets team
https://www.jqwidgets.comthanks but your example is for angular, I can still read it and use what I need, but you are basically doing the same. I started to get more problems with the layout not closing the floating dialogs correctly and it would save them even though they are not there. So, I went back to my spike to see if I could simulate the problem and guess what I was able to simulate ALL the problems. What I changed in my spike test was instead of the saving the data from the saveLayout to a local variable I saved it to a media, in the spike case I saved it to local storage. When I fresh the page and try to load it I get the famous double floating dialog (they are on top of each other, but you can drag the one away).
I have published a simple test for this as you have requested; https://github.com/Crisium/jqtest
clone it
npm inityou should now be able to reproduce the error. this was done on windows 10
good luck
are you making any progress on this?
please look at my spike test, cannot continue with jqwidgets before I get this solved. currently using easyui and would really like to make the change.
Hi Crisium,
After some testing we were able to found from where the problem was coming from and what the expected behaviour of the issue must be. So based on your github repository I have created a code snippet for you.
//In your ts file:
/// <reference path="../../../jqwidgets-ts/jqwidgets.d.ts" /> function createDockingLayout(DockingLayoutSelector, TreeSelector) { let layout = [{ type: 'layoutGroup', orientation: 'horizontal', items: [{ type: 'autoHideGroup', alignment: 'left', width: 80, unpinnedWidth: 200, items: [{ type: 'layoutPanel', title: 'Toolbox', contentContainer: 'ToolboxPanel' }, { type: 'layoutPanel', title: 'Help', contentContainer: 'HelpPanel' }] }, { type: 'layoutGroup', orientation: 'vertical', width: 500, items: [{ type: 'documentGroup', height: 400, minHeight: 200, items: [{ type: 'documentPanel', title: 'Document 1', contentContainer: 'Document1Panel' }, { type: 'documentPanel', title: 'Document 2', contentContainer: 'Document2Panel' }] }, { type: 'tabbedGroup', height: 200, pinnedHeight: 30, items: [{ type: 'layoutPanel', title: 'Error List', contentContainer: 'ErrorListPanel' }] }] }, { type: 'tabbedGroup', width: 220, minWidth: 200, items: [{ type: 'layoutPanel', title: 'Solution Explorer', contentContainer: 'SolutionExplorerPanel', initContent: function () { // initialize a jqxTree inside the Solution Explorer Panel let source = [{ icon: '../../../images/earth.png', label: 'Project', expanded: true, items: [{ icon: '../../../images/folder.png', label: 'css', expanded: true, items: [{ icon: '../../../images/nav1.png', label: 'jqx.base.css' }, { icon: '../../../images/nav1.png', label: 'jqx.energyblue.css' }, { icon: '../../../images/nav1.png', label: 'jqx.orange.css' }] }, { icon: '../../../images/folder.png', label: 'scripts', items: [{ icon: '../../../images/nav1.png', label: 'jqxcore.js' }, { icon: '../../../images/nav1.png', label: 'jqxdata.js' }, { icon: '../../../images/nav1.png', label: 'jqxgrid.js' }] }, { icon: '../../../images/nav1.png', label: 'index.htm' }] }]; let options: jqwidgets.TreeOptions = { source: source, width: 190 }; // creates an instance let myTree: jqwidgets.jqxTree = jqwidgets.createInstance(TreeSelector, 'jqxTree', options); } }, { type: 'layoutPanel', title: 'Properties', contentContainer: 'PropertiesPanel' }] }] }, { type: 'floatGroup', width: 500, height: 300, position: { x: 350, y: 250 }, items: [{ type: 'layoutPanel', title: 'Output', contentContainer: 'OutputPanel', selected: true }] }]; // initialization options - validated in typescript // jqwidgets.DockingLayoutOptions has generated TS definition let options: jqwidgets.DockingLayoutOptions = { width: 800, height: 600, layout: layout }; // creates an instance let myDockingLayout: jqwidgets.jqxDockingLayout = jqwidgets.createInstance(DockingLayoutSelector, 'jqxDockingLayout', options); $("#save").on("click", function () { console.log("saving"); var data = myDockingLayout.saveLayout(); var test = JSON.stringify(data, null, 2); localStorage.setItem("test", test); }); $("#load").on("click", function () { console.log("loading"); var test = localStorage.getItem("test"); let test2 = JSON.parse(test); myDockingLayout.loadLayout(test2) }); $("#create").on("click", function () { var uid = "3453-345-345-345-35"; myDockingLayout.addFloatGroup(300, 200, { x: 100, y: 100 }, 'layoutPanel', 'Rates', "<div id='" + uid + "'></div>" , 'initContent'); }) }
Also I used this demo for base https://www.jqwidgets.com/jquery-widgets-demo/demos/typescript/dockinglayout/typescript-dockinglayout.htm
And sorry for the late reply this was a bit specific case which needed a bit of evaluation.
Please, don’t hesitate to contact us if you have any questions!
Best Regards,
Yavor Dashev
jQWidgets team
https://www.jqwidgets.com@Yavor Dashev I am trying to see what the difference is?
I can see you are using a reference which indicates you did not use the npm installed version, since import the jqwidgets the reference cannot be used.
This also changes the behaviour for the methods loadLayout and saveLayout:
let myDockingLayout: jqwidgets.jqxDockingLayout = jqwidgets.createInstance(DockingLayoutSelector, ‘jqxDockingLayout’, options);
this is NOT possible when using import the saveLayout and loadLayout do not exist and can only be accessed using the query selector and type casting it to an any and do this:
let data = (<any>$(‘#jqxDockingLayout’)).jqxDockingLayout(‘saveLayout’);
The code you have supplied does not work with imports.
Peter
Hello Yavor,
Just for fun I changed the code to your suggestions (even though I know they are wrong, you do not use reference in this kind of a project).
anyways, compiles fine, but cannot run correctly. when you try and save the layout you get:
app.ts:114 Uncaught TypeError: docking_layout.saveLayout is not a function
at HTMLInputElement.<anonymous> (app.ts:114)
at HTMLInputElement.dispatch (jquery-3.6.0.min.js:2)
at HTMLInputElement.v.handle (jquery-3.6.0.min.js:2)that is why you need to call:
let data = (<any>$(‘#jqxDockingLayout’)).jqxDockingLayout(‘saveLayout’);I have updated the project on github so it has your suggestions (that do not work) in it.
You are using typescript in a very primitive way, which is more or less just a straight translation to javascript. Please run the example I have provided, I have added some extra comments to help guide you to the problems.
Please contact me if you need more info.
I still can’t move forward with this. I am at the point where I am using too much time fighting bugs with the jqx library. Going to see if I can find alternatives.
look at the jqwidget code:
https://github.com/jqwidgets/jQWidgets/blob/master/jqwidgets/jqxdockinglayout.js
just do a simple search and you will see there is no saveLayout or loadLayout
you are using the wrong code base.
the save and load are in the https://github.com/jqwidgets/jQWidgets/blob/master/jqwidgets/jqxlayout.js
but for some voodoo reason these functions are not available runtime. It seems like there is something that hasn’t been setup correctly.
If you look at the docking_layout in the console, you will clearly see that saveLayout and loadLayout __proto__ do not exist:
__proto__:
addEventHandler: ƒ (n,e)
addFloatGroup: ƒ (c,k,d,j,h,e,g)
addHandler: ƒ (p,e,n,o)
applyTo: ƒ (o,n)
base: null
baseType: “_jqxLayout”
createInstance: ƒ ()
defineInstance: ƒ ()
destroy: ƒ ()
getInstance: ƒ ()
isMaterialized: ƒ ()
isModern: ƒ ()
loadLayout: ƒ (e)
metaInfo: ƒ ()
propertyChangeMap: {}
refresh: ƒ ()
removeEventHandler: ƒ (n,e)
removeHandler: ƒ (o,e,n)
setOptions: ƒ ()
toThemeProperty: ƒ (e,n)
_addAutoHideGroupHandlers: ƒ (g,e,i,h)
_addBarAndLabel: ƒ (p)
_addClasses: ƒ ()
_addEdgeOverlaysHandlers: ƒ ()
_addOverlayHandlers: ƒ ()
_addTabbedGroupHandlers: ƒ (h,f)
_checkPosition: ƒ (k,p)
_clearTextSelection: ƒ ()
_closest: ƒ (d,c)
_createEdgeOverlays: ƒ ()
_createFloatGroup: ƒ (D,J,B,f,H,q,e)
_createOverlay: ƒ ()
_dropHandler: ƒ (r,x,z,D)
_dropToEdge: ƒ (c,d,w,y)
_dropToEmptyLayoutGroup: ƒ (f)
_floatAutoHideGroup: ƒ (f,g,b,e)
_floatTabbedGroup: ƒ (j,g,b)
_getDraggedWindowInformation: ƒ ()
_getFloatGroupItemSelection: ƒ (b)
_hideOverlays: ƒ ()
_interval: ƒ ()
_raiseEvent: ƒ (f,c)
_removeByDragHandler: ƒ (b,k,g,i,f)
_removeFloatGroupObject: ƒ (c)
_removeHandlers: ƒ ()
_setOptimalDimension: ƒ (d,b,c)
_showEdgeOverlays: ƒ ()
_trackFloatGroups: ƒ ()
_updateOverlayGroup: ƒ (c)
_updateOverlayGroups: ƒ ()
constructor: ƒ ()
__proto__: Objectand because they do NOT exist and you are using the wrong code base, your example fails completly.
-
AuthorPosts
You must be logged in to reply to this topic.