Dojo 1.7: BorderContainer и ContentPanes не работают внутри настраиваемого шаблона виджета

Это похоже на вопрос уже здесь, но я использую Dojo 1.7. Итак, я не могу заставить BorderContainer и ContentPanes работать внутри настраиваемого шаблона виджета. Это сводит меня с ума. Я попытался добавить миксины, предложенные в другом посте, и это не сработало.

Итак, у меня есть два примера. Первый - это одна страница, декларативно использующая додзё, и она отлично работает. Второй пример - это точно такая же страница, но я использую виджет для встраивания шаблона. Он отображает виджеты, но все они склеены в правом верхнем углу. Та же страница, те же стили. НО, когда я изменяю размер окна браузера, страница принимает форму. Еще не хватает бит, но так лучше

Большое спасибо

Это первый пример, который работает

<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Demo: Application Controller</title>
    <link rel="stylesheet" href="/js/tag/widgets/BorderWidget/css/demo.css" media="screen">
    <link rel="stylesheet" href="/js/tag/widgets/BorderWidget/css/style.css" media="screen">
    <link rel="stylesheet" href="/js/dijit/themes/claro/claro.css" media="screen">

    <!-- Configure Dojo -->
    <script type="text/javascript">
      var djConfig = {
        isDebug : true,
        parseOnLoad : true
      };
    </script>
    <script type="text/javascript" src="/js/dojo/dojo.js"></script>
    <script>
      dojo.require("dijit.layout.BorderContainer");
      dojo.require("dijit.layout.TabContainer");
      dojo.require("dijit.layout.ContentPane");
    </script>
  </head>
  <body class="claro">
    <div style="height:100%">
      <div id="appLayout" class="demoLayout" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design: 'headline'">
        <div class="centerPanel" id="tabs" data-dojo-type="dijit.layout.TabContainer" data-dojo-props="region: 'center', tabPosition: 'bottom'">
          <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="title: 'About'">
            <h2>Flickr keyword photo search</h2>
            <p>
              Each search creates a new tab with the results as thumbnails
            </p>
            <p>
              Click on any thumbnail to view the larger image
            </p>
          </div>
        </div>
        <div class="edgePanel" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region: 'top'">
          <div class="searchInputColumn">
            <div class="searchInputColumnInner">
              <input id="searchTerms" placeholder="search terms">
            </div>
          </div>
          <div class="searchButtonColumn">
            <button id="searchBtn">
              Search
            </button>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

А это второй пример использования виджета

<!DOCTYPE HTML>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Demo: Application Controller</title>
    <link rel="stylesheet" href="/js/tag/widgets/BorderWidget/css/demo.css" media="screen">
    <link rel="stylesheet" href="/js/tag/widgets/BorderWidget/css/style.css" media="screen">
    <link rel="stylesheet" href="/js/dijit/themes/claro/claro.css" media="screen">

    <!-- Configure Dojo -->
    <script type="text/javascript">
      var djConfig = {
        isDebug : true,
        parseOnLoad : true,
        paths : {
          'tag' : '../tag/widgets/BorderWidget'
        }
      };
    </script>
    <script type="text/javascript" src="/js/dojo/dojo.js"></script>
    <script>
      dojo.require("dijit.layout.BorderContainer");
      dojo.require("dijit.layout.TabContainer");
      dojo.require("dijit.layout.ContentPane");
      dojo.require('tag.Widget');

      dojo.ready(function() {
        new tag.Widget().startup();
      });
    </script>
  </head>
  <body class="claro">

  </body>
</html>

Это код виджета

define('tag/Widget', 
[
  'dojo', 
  'dijit/_Widget', 
  'dijit/_TemplatedMixin', 
  'dijit/_WidgetsInTemplateMixin',
  'dijit/layout/BorderContainer',
  'dijit/layout/TabContainer',
  'dijit/layout/ContentPane'
], 
function(d) {
  //The widget contructor will be returned
  return d.declare('tag.Widget', 
  [
    dijit._Widget, 
    dijit._TemplatedMixin, 
    dijit._WidgetsInTemplateMixin
  ], 
  {
    templateString : d.cache("tag", "templates/template.html"),

    postCreate : function() {
      this.inherited(arguments);
      var domNode = this.domNode;
    },

    startup : function(args) {
      this.inherited(arguments);
      this.placeAt(dojo.doc.body);
    }


  });
});

Это шаблон для виджета

<div style="height:100%">
  <div id="appLayout" class="demoLayout" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design: 'headline'">
    <div class="centerPanel" id="tabs" data-dojo-type="dijit.layout.TabContainer" data-dojo-props="region: 'center', tabPosition: 'bottom'">
      <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="title: 'About'">
        <h2>Flickr keyword photo search</h2>
        <p>
          Each search creates a new tab with the results as thumbnails
        </p>
        <p>
          Click on any thumbnail to view the larger image
        </p>
      </div>
    </div>
    <div class="edgePanel" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region: 'top'">
      <div class="searchInputColumn">
        <div class="searchInputColumnInner">
          <input id="searchTerms" placeholder="search terms">
        </div>
      </div>
      <div class="searchButtonColumn">
        <button id="searchBtn">
          Search
        </button>
      </div>
    </div>
  </div>
</div>

person screenm0nkey    schedule 27.10.2011    source источник


Ответы (8)


Возможно, вам потребуется явно вызвать автозагрузку для виджетов макета BorderContainer и ContentPane в вашем собственном startup() методе. Также вы, вероятно, захотите всегда иметь this.inherited(arguments) в любом из методов жизненного цикла виджета, если вы переопределяете и наследуете метод.

startup : function(args) {
    this.inherited(arguments);
    //console.log('asdasd')
    dojo.empty("body");
    this.placeAt('body');

    this.subContainerWidget.startup();
    //I think the border container will automatically call startup on its children 
    //(the content panes), but you may also need to call startup on them.
}

Кроме того, как упоминалось в @missingno, вы, вероятно, не хотите очищать <body> и заменять его во время запуска виджета в качестве общей возможности повторного использования.

person BuffaloBuffalo    schedule 27.10.2011
comment
Привет, Буффало, извини за задержку с ответом. Обычно я не так долго отвечаю. Dojo отображает виджеты, но они не выглядят одинаково. Я отредактирую свой исходный пост. - person screenm0nkey; 31.10.2011
comment
+1 за полезный ответ. Я прочитал сообщение участника додзё на сайте додзё, в котором говорилось, что использование шаблонов виджетов для создания макета не совсем готово и работает не очень хорошо. К сожалению, он не сказал, что является правильным, поэтому я создал макет программно, и он отлично проснулся. Вроде. - person screenm0nkey; 03.11.2011

У меня была очень похожая проблема с настраиваемым виджетом и BorderContainers внутри, и она, наконец, сработала после того, как я унаследовал BorderContainer вместо BaseWidget или _Widget. Надеюсь, это также поможет в вашем случае!

person skython    schedule 18.01.2012
comment
Отлично - это может быть правило, которое вы унаследовали от верхнего элемента вашего шаблона, если это шаблонный виджет, чтобы он соответствующим образом отреагировал. - person unludo; 04.07.2013
comment
@unludo Как ты это делаешь? - person sjs; 10.05.2016

Я создаю свои шаблонные пользовательские виджеты, которые содержат BorderContainers с окружающим div (потому что я не мог заставить работать BorderContainer верхнего уровня), например:

<div style="height: 100%;">
<div style="height: 100%;" data-dojo-type="dijit/layout/BorderContainer"
     data-dojo-attach-point="bc"
     data-dojo-props="design: 'headline', gutters: false">
    <div data-dojo-type="dijit/layout/ContentPane"
         data-dojo-props="region: 'top'">
    </div>
    <div data-dojo-type="dijit/layout/ContentPane"
         data-dojo-props="region: 'center'">
    </div>
</div>

I had the exact same layout problems (BorderContainer would only layout correctly after page resize), until I realized (thanks to the answer by John Brinnand above) that I need to forward any resize calls from dijit to the "inner" BorderContainer. So what I did was to implement a resize method in my widget ("bc" is the BorderContainer widget, brought in via data-dojo-attach-point as seen in the above code):

        resize: function () {
        this.bc.resize(arguments);
        this.inherited(arguments);
    }

и о чудо: все работает нормально.

(я использую dojo 1.9, но это должно работать для dojo> = 1.7)

person Oliver    schedule 07.01.2014
comment
Привет Оливер, спасибо, что поделился. У меня такая же проблема, и я попробовал ваше решение. Однако функция изменения размера, которую я создал для своего виджета, не вызывается. Вам нужно каким-то образом подключить его или унаследовать определенный класс (я наследую _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin). Благодарность! - person Kate; 20.05.2014
comment
@Simon: извините, поздний ответ ... но нет, я просто наследую _WidgetBase, _TemplatedMixin и _WidgetsInTemplateMixin. Вы startup() свой виджет? - person Oliver; 06.07.2015

BorderContainer - это виджет макета, размер которого необходимо задавать динамически. Вы перезаписали метод запуска, и я уверен, что это по крайней мере одна из проблем.

Поскольку содержимое вашего метода запуска на самом деле не запускается, я предлагаю вам просто попробовать удалить или переименовать его (чтобы открыть исходный запуск).

d.declare(...)|{
    ...
    toFullScreen: function(){
        dojo.empty("body");
      this.placeAt('body');
    }
}

var w = new FlickApiView({...});
w.toFullScreen();
w.startup();

Изменить (для новой задачи):

я нахожу

startup : function(args) {
  this.inherited(arguments);
  this.placeAt(dojo.doc.body);
}

Это вызывает подозрение, поскольку все изменение размера выполняется в части this.inherited до того, как виджет будет фактически размещен (поэтому изменение размера изначально не работает)

Вы можете попробовать изменить порядок здесь, но я думаю, что лучше полностью удалить метод запуска и изменить основной на

var w  = new tags.Widget();
w.placeAt(dojo.body());
s.startup();
person hugomg    schedule 27.10.2011
comment
Приносим извинения за задержку с ответом. Я не смог ответить. В любом случае, ваш совет полезен, но все равно не работает. Я собираюсь редактировать свой пост выше. Dojo отображает виджеты, но они полностью не отформатированы. - person screenm0nkey; 31.10.2011
comment
+1 Спасибо за ответ отсутствует. Я разработал способ и разместил его здесь. - person screenm0nkey; 08.11.2011

Способ создания макета заключается не в использовании шаблонных виджетов, а в том, чтобы делать это программно. На самом деле я нигде этого не нашел, но я также не мог найти никого, кто бы заставил меня сделать это вот так;

// view
define('tag/views/CampaignTest/layout', [
  'dojo',
  'dbp/widgetStore',
  'dijit/layout/BorderContainer',
  'dijit/layout/TabContainer',
  'dijit/layout/ContentPane',
  'dojo/NodeList-manipulate'
],

function(dojo, widgetStore, BorderContainer, TabContainer, ContentPane) {
  return {
    create : function (layoutName) {
      var deferred = new dojo.Deferred(),
          add = dojo.partial(widgetStore.add, layoutName);

      dojo.query("body").prepend("<div id='appLayout' class='demoLayout'></div>");

      var appLayout = add(
        new BorderContainer({
          design: "headline"
        }, dojo.byId("appLayout"))
      );


      // create the TabContainer
      var contentTabs = add(
        new dijit.layout.TabContainer({
          region: "center",
          id: "contentTabs",
          tabPosition: "bottom",
          "class": "centerPanel",
          href: "contentCenter.html"
        })
      );

      // add the TabContainer as a child of the BorderContainer
      appLayout.addChild( contentTabs );

      // create and add the BorderContainer edge regions
      appLayout.addChild(
        add(
          new dijit.layout.ContentPane({
            style : "height:50px",
            region: "top",
            id : "top",
            "class": "edgePanel",
            content: "Header content (top)"
          })
        )
      );

      appLayout.addChild(
        add(
          new dijit.layout.ContentPane({
            style : "height:50px",
            region: "top",
            id : "top2",
            "class": "edgePanel",
            content: "Next content (top)"
          })
        )
      );

      appLayout.addChild(
        add(
          new dijit.layout.ContentPane({
              region: "left",
              id: "leftCol",
              "class": "edgePanel",
              content: "Sidebar content (left)",
              splitter: true
          })
        )
      );

      contentTabs.addChild(
        add(
          new dijit.layout.ContentPane({
            title: "Start"
          }, dojo.byId("startContent"))
        )
      );

      // not even sure this is necessary but I
      // check to make sure layout has finished
      (function check(){
        setTimeout(function(){
          appLayout.domNode ? deferred.resolve() : check();
        }, 10);
      })();


      appLayout.startup();

      return deferred;
    }
  };
}); 
person screenm0nkey    schedule 03.11.2011
comment
Вы проверяли ответ @skython? У меня он работает с шаблонным виджетом, и это überkool :) - person unludo; 04.07.2013

В dojo 1.7 изменилась конструкция и расположение виджетов. Существует следующий порядок: создать виджет, добавить его к родительскому элементу, запустить, изменить размер. До версии 1.7 последовательность действий при запуске виджета была иной.

В вашем примере:

  • Создайте BorderContainer: var bc = new dijit.layout.BorderContainer ({...});
  • Добавьте его к родительскому элементу: parent.addChild или parent.appendChild (bc)
  • запускаем: bc.startup ();
  • измените его размер: bc.resize ();

Та же последовательность будет применяться к дочерним элементам контейнера границы:

  • Создайте панель содержимого: var cp1 = new dijit.layout.ContentPane ({...});
  • Добавьте его к родительскому элементу: bc.addChild (cp1);
  • Запустите панель содержимого: cp1.startup (); // может и не понадобиться, но это не повредит
  • Измените размер панели содержимого: cp1.resize (); // может и не понадобиться, но это не повредит
  • Перезапустите контейнер границы: bc.startup (); // это важно.
  • Измените размер контейнера границы: bc.resize (); // критически важно: без него макет не отображается.

Запускать уже запущенный контейнер может показаться излишним. И вы можете поиграть с этой последовательностью, чтобы найти, что нужно, а что нет. Однако resize () имеет решающее значение. Без него размер макета будет неверным, и он не будет отображаться.

Примечание: этот пример подразумевает программное построение и подключение виджетов додзё.

person John Brinnand    schedule 27.12.2011

Создание подкласса BorderContainer вместо _Widget как предложенный skython, похоже, решил большинство проблем. Несколько сбоев остались, как некоторые границы, которые не прорисовывались при первоначальном рисовании виджета, поэтому я вызвал resize() для дочерних виджетов из метода startup(). Обратите внимание, что немедленный вызов изменения размера из метода запуска не работает, но использование setTimeout() с задержкой 0 работает:

startup : function(args) {
    // Hack to force widget to initially draw properly.
    array.forEach(this.getChildren(), function(elem, id) {
        setTimeout(elem.resize, 0);
    });

    this.inherited(arguments);
},
person Leftium    schedule 16.04.2012

Я потратил 4 часа, чтобы наконец заставить его работать как декларативным, так и программным способами. Ключ в том, что вы должны вызвать yourBorderContainerObj.startup () или .resize () после того, как его элемент dom будет на месте (видимым?).

Я пытался создать шаблонный виджет, содержащий BorderContainer и несколько ContentPanes, и поместить его в диалоговое окно. Сначала я не мог заставить BorderContainer и ContentPanes правильно отображаться, когда отображается диалоговое окно, они были инициализированы и присвоены правильные имена классов, но эффекты css, похоже, не применялись.

Я заставляю шаблонный виджет работать, делая это в виджете:

resize: function() {
      this.inherited(arguments);
      this.myBorderContainerObj.resize();
}

Вот и все. Тогда BorderContainer и ContentPanes работают должным образом.

Кстати, я использую 1.8.3.

person zhywu    schedule 19.04.2013