Dojo changing scope of data dojo attach point - dojo

Can you specify/change the scope of a data-dojo-attach-point to something other than the current widget?
eg. I have a templated widget called parent. In that template I have another widget called child1. Nested in child1, I have some widgets. I want to bind these nested widgets to child1 rather than parent.
Edit:
<div data-dojo-type="someContainer" data-dojo-attach-point="parent">
<div data-dojo-type="somePane" data-dojo-attach-point="child1">
<span data-dojo-attach-point="(I want to be bound to somePane)"></span>
</div>
</div>
I'd like to bind the "span" to somePane without having to go through someContainer.

Separate the span into it's own widget and you can add them to the parent like this.
Parent template that contains the content panes
<div style="width: 100%; height: 100%;">
<div data-dojo-type="dijit/layout/LayoutContainer" style="width: 100%; height: 100%" data-dojo-attach-point="mainNode">
<div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top'" >
<div >
<!--some content-->
</div>
</div>
<div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'" id="center">
<div data-dojo-attach-point="centerNode"></div>
</div>
</div>
</div>
In postCreate method of your parent widget create new instance of the child and attach it to the parent
define([
"dojo/_base/declare",
"dijit/_WidgetBase",
"dijit/_TemplatedMixin",
"dijit/_WidgetsInTemplateMixin",
"dojo/text!./templates/Parent.html",
"somePath/childWidget",
'dojo/domReady!'
], function (
declare,
_WidgetBase,
_TemplatedMixin,
_WidgetsInTemplateMixin,
parentTemplate,
ChildWidget
) {
return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
templateString: parentTemplate,
postCreate: function () {
this.inherited(arguments);
var myChild = new ChildWidget();
myChild.placeAt(this.centerNode);
myChild.startup();
}
});
});
Then because the span is inside it's own widget, you might have a template for it that looks like this
<div>
<span data-dojo-attach-point="spanNode"></span>
</div>
So now the span attach point is decoupled from the parent. You can directly reference the 'spanNode' from within the widget you created for the span.
Declaratively,
in your childWidget that contains the span you can give give it a class name like this
return declare("childWidget", [_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], { ...
And in the parent template instead of using an attach point to attach the widget use data-dojo-type like this
<div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'" id="center">
<div data-dojo-type="childWidget"><!--child widget will get attached here--></div>
</div>

Related

How to conditionally render multiple components based on route without affecting layout in vue3

I have a navbar and two side menus which I use in multiple pages. But for a number of pages I don't want to have the side menu.
I have tried using v-if with $router.name, but because I was using a grid system, the layout would break. Then also it was impossible to add more than one component to not render the side menus.
This is the template:
<template>
<TheNavbar/>
<div class="container">
<TheLeftMenu/>
<router-view/>
<TheRightMenu/>
</div>
</template>
My solution to avoid the grid system to squash the router-view component was to divide the template in two, one using the sidemenus, the other without them.
Then in order to have multiple pages to not load the side menus I used a computed property to hold an array with all the routes to not render the side menus:
<template>
<div v-if="blockedRoutes.includes($route.name) == false">
<TheNavbar/>
<div class="container">
<TheLeftMenu/>
<router-view/>
<TheRightMenu/>
</div>
</div>
<div v-else>
<TheNavbar/>
<router-view/>
</div>
</template>
computed: {
blockedRoutes () {
return ['Register', 'SignIn', 'About']
}
}
you can use the simple method of a flex container;
<template>
<router-view v-slot="{ Component, route }">
<div class="holder">
<div>
<TheLeftMenu/>
</div">
<div class="main">
<transition name="fade" mode="out-in"><component :is="Component" /></transition>
</div>
<div v-if="!route.meta.hideRmenu">
<TheRightMenu/>
</div>
</div>
</router-view>
</template>
<style>
.holder{
display : flex;
width : 100%;
/*if you want your container not to grow with the page do the following*/
overflow: hidden;
height : 100vh;
}
.holder .main{
flex : 1;
flex-direction: row;
/*if you want your container not to grow with the page do the following*/
max-height : 100vh;
overflow : auto;
}
.holder :not(.main){
min-width: 32px;
}
</style>
This way you can, if you want, also add transitions.
If you don't want to use transitions, you just need to remove the transitions tags.
This aproach uses is focused for Vue 3 and uses Scoped Slots

Vue.js pass local loop variable to v-bind:style

I loop through a list and would like to set a background image according to a property in this list.
But in v-bind:stlye the property isn't defined.
How can I pass it?
<div class="content" v-bind:key="slide.id" v-for="slide in show.slides">
<div class="slide">
<div class="model"
:style="{ backgroundImage:
`url(${strapiUrl + slide.model_media.Media.url})` }">
<div class="title">{{slide.title}}</div>
</div>
</div>
Perhaps it is simply easier to abstract the entire style binding into a method. In your template, you can simply do this:
<div class="model" v-bind:style="modelStyle(slide)">
Then, in your component, create a modelStyle() method:
modelStyle: function(slide) {
return {
backgroundImage: url(`${this.strapiUrl}${slide.model_media.Media.url}`);
};
}

Presentation Component in Vue2

I want to display all my forms and info pages in floating sidebox.
I don't want to copy and paste the floating sidebox html to all the places. So I want to create a component which acts as container to my forms or info pages.
This is the sample code for form.
<div class="floating-sidebox">
<div class="sidebox-header">
<div class="sidebox-center">
<h3 class="title">{{ title }}</h3>
</div>
</div>
<div class="sidebox-content">
<div class="sidebox-center">
<!-- This is the actual content. Above container code is common for all forms. -->
<vue-form-generator :schema="schema" :model="model" :options="{}"></vue-form-generator>
</div>
</div>
<div class="floating-sidebox-close" #click="cancel"></div>
</div>
<div class="floating-sidebox-overlay"></div>
In above code, I uses vue-form-generator to generate the form. The floating-sidebox elements are common for all forms and info pages. I want to abstract it by Presentational component.
How could I do it Vue2?
Define a component that wraps all your "floating-sidebox" components. You can access the "floating-sideboxes" via this.$children and use their title etc. as navigation placeholder. Since $children is an array you can easily represent the currently visible entity with and index
...
data: function() {
sideboxes: [],
currentIndex: null
},
...
mounted: function() {
this.sideboxes = this.$children;
this.currentIndex= this.$children.length > 0 ? 0 : null;
},
...
computed: {
current: function() {
return this.currentIndex ? this.sideboxes[this.currentIndex] : null;
}
}
You can then bind in the template of the wrapping view
<ul>
<li v-for="(sidebox, index) in sideboxes" #click="currentIndex = index"><!-- bind to prop like title here --></li>
</ul>
<div>
<!-- binding against current -->
</div>
JSfiddle with component https://jsfiddle.net/ptk5ostr/3/

custom dojo widget in a loop; html not flowing properly

I loop over an array of objects, adding a custom widget to the page each time. I need to put a "space" div atop each widget, and "pageBreak" div at the bottom of each widget. Here is the creation/placement of the widgets inside the loop:
var placeIt = true;
array.forEach(data.features,function(feat,i){
var newDijit = new printDijit({}, domConstruct.create('div'));
newDijit.placeAt(dom.byId('printWindow'));
newDijit.startup();
if (placeIt){
newDijit.cNode(domConstruct.create("div",{class:'space',innerHTML:'a'}));
placeIt = false;
}else{
newDijit.cNode(domConstruct.create("div",{class:'break',innerHTML:'a'}));
placeIt = true;
}
});
Here is the widget:
require([
"dojo/parser",
"dojo/ready",
"dojo/_base/declare",
"dojo/dom-construct",
"dijit/_WidgetBase",
"dijit/_TemplatedMixin",
"dijit/_WidgetsInTemplateMixin"
], function(parser, ready, declare, domConstruct, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin){
declare("printDijit", [_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin],{
templateString: dojo.cache(new dojo._Url("printDijit.html")),
cNode: function(htmlCnode){
domConstruct.place(htmlCnode,this.domNode.id,'before');
}
});
});
Here is the widget template; printDijit.html
<div class="printTemplateCls" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline'">
<div class="printHeaderCls" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top'">Top-header</div>
<div class="printInputsCls" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'">Top-right pane</div>
<div class="printBottomPaneCls" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="region:'bottom', gutters:false">
<div class="printPicCls" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'leading'" style="width:342px">Bottom-left pane</div>
<div class="printMapCls" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'"></div>
</div>
The html in fireBug looks fine, but the 2nd and onward space/break div's are behind the widget and dont' flow correctly (see screenshot). If the widgets declared everything is good.
Anyone know what's going on here?
had to wrap the template in an outer div, like below. I would assume this is because the original root element was also a widget.
<div>
<div class="printTemplateCls" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline'">
<div class="printHeaderCls" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top'">Top-header</div>
<div class="printInputsCls" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'">Top-right pane</div>
<div class="printBottomPaneCls" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="region:'bottom', gutters:false">
<div class="printPicCls" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'leading'" style="width:342px">Bottom-left pane</div>
<div class="printMapCls" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'"></div>
</div>
</div>

dijit widgets inside a custom widget -- handling their events

JS:
define(["dojo/_base/declare","dojo/dom",
"dijit/_Widget", "dijit/_TemplatedMixin",
"dojo/text!./templates/MainViewWidget.html",
"dijit/layout/TabContainer", "dijit/layout/ContentPane","dijit/layout/BorderContainer","dijit/form/TextBox", "dijit/layout/AccordionContainer"],
function(declare, dom, _Widget, _TemplatedMixin, template){
return declare("package.MainViewWidget", [_Widget, _TemplatedMixin], {
widgetsInTemplate: true,
templateString: template,
constructor: function(){
},
startup: function(){
},
search: function(evt){
alert('hi');
alert(evt);
}
});
});
templates/MainViewWidget.html:
<div class="mainContainer">
<div data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design:'sidebar', gutters:true, liveSplitters:true" style="width:100%;height:100%;">
<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'left', splitter:true">
<h2>List of trips</h2>
<br />
<input type="text" data-dojo-type="dijit.form.TextBox" data-dojo-props="placeHolder:'Search...'" data-dojo-attach-event="onchange:'search'"/>
<br />
</div>
<div data-dojo-type="dijit.layout.TabContainer" data-dojo-attach-point="tabContainerDiv" data-dojo-props="region: 'center', tabPosition: 'top', tabStrip:'true', style:'width:80%;height:100%'">
<div data-dojo-type="dijit.layout.ContentPane" title="Summary" data-dojo-props="selected:'true', title:'About'">Welcome. Navigate through the Left pane.</div>
</div>
</div>
</div>
The thing is, I want to capture events on the TextBox. I was looking to do this with just markup as you can see from data-dojo-attach-event="onchange:'search'". I have tried many variations of this and I can't get it to work. Basically what I want is to define a function in JS and attach it as handler in the markup. Please help.
This isn't supported, sadly. I just spent about two hours discovering this. Any node in your template with a data-dojo-type attribute is ignored by _TemplatedMixin._attachTemplateNodes (see line 177). In other words, data-dojo-attach-event will only bind to plain DOM nodes (not Dijits).
This at least applies to v1.8. The attach processing is different in v1.9 (there's an _AttachMixin), so it might work there.
Try:
data-dojo-attach-event="onChange:search"
Camelcase onChange, and no quotes around search.