Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Isolating objects in TabSet's tabs

    My app contains a TabSet with many tabs. These tabs are created dynamicly basing on data. Content of each tab is created on the server. I use ViewLoader for that.
    Code:
    centerTabSet.addTab({
    	title: entityTypeDesc,
    	autoDraw: true,
    	canClose: true,
    	ID: "centerTabSet_" + entityTypeName,
    	pane: isc.ViewLoader.create({
    		viewURL: "<%: Url.Content("~") %>ViewLoader/getListPart?entityType=" + entityTypeName
    	})
    Content is created on the server bacause it dynamical. It's autogenerated UI (kind of scaffolding).
    ViewLoader controller (which returns UI for tabs) creates each time similar UI based on url's parameters ('entityType' here).
    Returned UI contains several connected isc-objects: DynamicForm, ListGrid and ContextMenu.
    Something like this (code between <%%> is server asp.net mvc code):
    Code:
    var datasource = isc.DataSource.create({
    	dataFormat: "xml",
    	dataURL: "<%= ViewData["DataURL"]%>",
    	recordXPath: "//Rows/R",
    	fields:<%= ViewData["FieldsJsonArray"] %>,
    });
    var filter = isc.SearchForm.create({
    	dataSource: "datasource",
    	fields: <%= ViewData["FilterFieldsJsonArray"] %>,
    	saveOnEnter: true,
    	submitValues : "refreshButton.doSearch()"
    });
    
    var listContextMenu = isc.Menu.create({
    	data : [
    		{title: "Edit", enableIf: "list.getSelectedRecord() != null", click: "openEditorInDialog()"},
    	]	
    });
    
    var list = isc.ListGrid.create({
    	selectionType: "single",
    	contextMenu: listContextMenu,
    	autoFetchData: true,
    	dataSource: "datasource"
    });
    It works fine untill there's only one tab. But as a user opens a next tab object names start dublicating. And ListGrid on some tab starts using ContextMenu from tab has been opened previously and so on.
    I can understand why that's happening, just because all objects are in the global scope.

    My question is about what are good patterns&practices in such situations. How to isolate objects on deferent tabs?
    One approach I can see is to use string IDs instead of variables and generate unique ID in server code. That would probably work in general but a problem I can see is using IDs in string methods.
    Let's look a ContextMenu's item. It has enableIf attibute with JS-code:
    enableIf: "list.getSelectedRecord() != null"
    "list" is a name in global space. So I have to write something like this:
    "list<%= ViewData["UniqueId"] %>.getSelectedRecord() != null"
    i.e. combine client with server. It's ugly!

    Is there any other approaches?

    #2
    I would rewrite your code like this:
    Code:
    var datasource = isc.DataSource.create({
    	dataFormat: "xml",
    	dataURL: "<%= ViewData["DataURL"]%>",
    	recordXPath: "//Rows/R",
    	fields:<%= ViewData["FieldsJsonArray"] %>,
    });
    var filter = isc.SearchForm.create({
    	dataSource: datasource,
    	fields: <%= ViewData["FilterFieldsJsonArray"] %>,
    	saveOnEnter: true,
    	submitValues : "refreshButton.doSearch()"
    });
    
    var list = isc.ListGrid.create({
    	selectionType: "single",
    	autoFetchData: true,
    	dataSource: datasource
    });
    
    var listContextMenu = isc.Menu.create({
    	data : [
    		{title: "Edit", enableIf: list.getID()+".getSelectedRecord() != null", click: "openEditorInDialog()"},
    	]
    });
    
    list.setProperty("contextMenu", listContextMenu);

    Comment


      #3
      Thank a lot, that helps. It's much simplier.

      But what I can't overcome is dependencies inside custom functions.
      There's a button with click handler which reloads ListGrid.
      I understand that I can use string methods for its handler. It's clear and it work. But if handler's body is complex than using string methods is not very handy. That's because I want to create a real function ("doSearch" below):
      Code:
      var filter = isc.SearchForm.create({
      	dataSource: datasource,
      	fields: <%= ViewData["FilterFieldsJsonArray"] %>,
      	saveOnEnter: true,
      	submitValues : "refreshButton.doSearch()"
      });
      var refreshButton = isc.IButton.create({
      	ID: "refreshButton" + uid,
      	title: "Обновить",
      	click: "this.doSearch()",
      	doSearch: function() {
      		var criteria = filter.getValues();
      		list.setCriteria(criteria);
      		list.invalidateCache();
      	}
      });
      doSearch function needs to get references to list and filter. But it can't use 'list' and 'filter' variables. And it can't use theire IDs. In both cases doSearch would use list/filter from another tab.
      That is I need some way to bind refreshButton object with references to list and filter right after they've been created.
      I tried set custom properties :
      Code:
      var refreshButton = isc.IButton.create({ _filter: filter })
      and
      Code:
      refreshButton.setProperty("_filter", filter);
      and use them inside doSearch.
      That doesn't work (and it probably shouldn't, I don't know).

      May you have any idea how to do that?

      Comment


        #4
        Code:
        var tabContext = {};
        tabContext.list = ListGrid.create({
          ...,
          someEventHandler: function() {
            this.context.button.doSomething();
          },
          context: tabContext
        })
        
        tabContext.button = IButton.create({
          ...,
          click: function() {
            this.context.list.fetchData();
          },
          context: tabContext
        });
        In this case, objects atributes would be bound at declaration time and code would no longer rely on global variables.

        Comment


          #5
          I tried to inject list/filter references into button object but forgot using "this" inside its function.

          Works like a charm. Thanks a lot for your help!

          Comment

          Working...
          X