How to create a ribbon with FlamingoBuilder in Griffon? - groovy

I'm currently trying to create an application with Griffon 0.9.5 and the FlamingoBuilder.
I've the changed the value of frameClass in Application.groovy to 'org.jvnet.flamingo.ribbon.JRibbonFrame' and tried a few things in order to add a ribbon to the application window.
My first attempt was creating a ribbonTask node with nested ribbonBand nodes. The application starts but the buttons are not shown.
application(title: 'test01',
preferredSize: [320, 240],
pack: true,
locationByPlatform: true,
iconImage: imageIcon('/griffon-icon-48x48.png').image,
{
ribbonTask(title: 'Start') {
ribbonBand(id: 'fooBarBand', title: 'FooBar', image: imageIcon('/griffon-icon-48x48.png').image) {
commandButton(id: 'fooButton', text: 'Foo', image: imageIcon('/griffon-icon-48x48.png').image)
commandButton(id: 'barButton', text: 'Bar', image: imageIcon('/griffon-icon-48x48.png').image)
}
}
// add content here
label('Content Goes Here') // delete me
}
)
In my second attempt I explicitly create a RibbonTask and call addTask. The buttons are shown. However, I'm not sure if this is really the Griffon-way of doing things.
Question: Is there a better way to create a ribbon?
application(title: 'test01',
preferredSize: [320, 240],
pack: true,
locationByPlatform: true,
iconImage: imageIcon('/griffon-icon-48x48.png').image,
{
ribbonBand(id: 'fooBarBand', title: 'FooBar', image: imageIcon('/griffon-icon-48x48.png').image) {
commandButton(id: 'fooButton', text: 'Foo', image: imageIcon('/griffon-icon-48x48.png').image)
commandButton(id: 'barButton', text: 'Bar', image: imageIcon('/griffon-icon-48x48.png').image)
}
current.ribbon.addTask new RibbonTask('Start', fooBarBand)
// add content here
label('Content Goes Here') // delete me
}
)
I then tried adding a ribbonApplicationMenu with the following code snippet:
ribbonApplicationMenu(id: 'appMenu') {
ribbonApplicationMenuEntryPrimary(id: 'quitMenuEntry', text: 'Quit',
entryKind: JCommandButton.CommandButtonKind.ACTION_ONLY,
image: imageIcon('/griffon-icon-48x48.png').image)
}
However, it doesn't work. I get the following runtime exception:
java.lang.RuntimeException: Failed to create component for
'ribbonApplicationMenuEntryPrimary' reason:
groovy.lang.MissingPropertyException: No such property: text for
class:
griffon.builder.flamingo.factory.RibbonApplicationMenuEntryPrimaryFactory
The documentation of FlamingoBuilder states that there is a text property and when I remove the text property I get an exception because the text property must be set. I'm a little bit at loss. What's wrong with this code snippet?

I'm afraid the first issue is related to the application() node factory vs ribbonFrame() factory. You see, Griffon assumes the frame subclass to behave like any other regular JFrame however JRibbonFrame handles its children in a different way. This is not know to ApplicationFactory so it "fails" to add ribbon tasks unless you add them manually as you show in the second snippet.
This problem can be fixed by moving the parent/child relationship code from ribbonFrame() to ribbonBand/ribbonTask factories. This requires a new release of FlamingoBuilder.
Now on the second problem, that appears to be a bug on our side. Considering that FlamingoBuilder should be updated in any case we'll fix this problem too.

Related

How to access custom cms element config values in Shopware 6?

FYI: Products is my cms element name.
As shown in shopware 6 guides, I have created a file
DataResolver/ProductsCmsElementResolver.php
which has an enrich method which helps to extend data. In there I try to access the configs of my custom cms element with:
$config = $slot->getFieldConfig();
$productListType = $config->get('products')->getValue();
That, however always returns the default value that was set during the registration of the element:
Shopware.Service('cmsService').registerCmsElement({
name: 'products',
label: 'das.elements.customProductsElement.label',
component: 'sw-cms-el-products',
configComponent: 'sw-cms-el-config-products',
previewComponent: 'sw-cms-el-preview-products',
defaultConfig: {
products: {
source: 'static',
value: ''
}
}
});
I did it exactly as it is shown in the following guides:
https://developer.shopware.com/docs/guides/plugins/plugins/content/cms/add-cms-element
https://developer.shopware.com/docs/guides/plugins/plugins/content/cms/add-data-to-cms-elements#create-a-data-resolver
Could anyone share a sample of code where you get the value of config as a variable and not static value?
What I was doing wrong was that I forgot to write the .value in computed methods:
computed: {
products() {
return this.element.config.products.value;
}
},
However I also found such function call in shopware source codes which was not mentioned in the docs:
methods: {
createdComponent() {
this.initElementConfig('youtube-video');
this.initElementData('youtube-video'); // this line was not present in docs
}
}
I assume you haven't done any further handling of the product data in your config component, as you do not mention it.
I suggest having a look at the default cms components like for example shopware/administration/Resources/app/administration/src/module/sw-cms/elements/product-slider/config/index.js where you can see how product data is handled :)

Is there any way to close an overlay

I am using react-native-navigation v2 and showing an overlay,
and at some place in my code. i want to show an over lay and later disable it .
for example to show loading.
I have Read the docs and followed it as much I could understand. I can show an overlay but can not dismiss it. A warning always comes up saying - overlay with id offlineoverlay1 was not found.
async showOverLay(){
await Navigation.showOverlay({
component: {
id: "OfflineOverlay1",
name: 'Uploading',
options: {
overlay: {
interceptTouchOutside: true
}
}
}
});
}
async closeOverLay(){
await Navigation.dismissOverlay('OfflineOverlay1')
}
Expected Result- the overlay should be closed when calling closeOverLay() function
you have defined
component :{id:"OfflineOverlay1"} // the use of ""
but you have called like this,
Navigation.dismissOverlay('OfflineOverlay1') // & the use of ''

selectize.js lockOptgroupOrder throwing exception

I have a selectize where I set optgroups, give them an $order, and then try to set lockOptgroupOrder, which ends up throwing an exception: "Uncaught TypeError: Cannot read property '$order' of undefined".
This all works perfectly before I try to use lockOptgroupOrder (except that it sorts wrong). I cannot figure out why it can't find $order, when I'm clearly passing $order in as part of optgroups. (I've also tried setting optgroupOrder: ['first', 'recents', 'favorites', 'all'] with no luck.)
var stuff = $('#stuff').selectize({
optgroups: [
{value: 'first', label: '', $order: 1},
{value: 'recents', label: 'Recents', $order: 2},
{value: 'favorites', label: 'Favorites', $order: 3},
{value: 'all', label: 'All', $order: 4}
],
optgroupField: 'type',
lockOptgroupOrder: true,
//more things like load() and onChange()...
});
The error:
It's breaking in this loop:
I have exhausted all other forms of researching this error. Has anyone come across this before?
So after many, many hours of googling, chrome debugging, and general crying, I figured out the issue and now I'm posting my solution in case anyone else comes across this error.
Thanks to this discussion board:
lockOptgroupOrder breaks onChange
I was able to piece together that one of my data elements was missing a 'type' field (optgroupField). I stepped through all 1350 options before realizing that it was actually the default option I added to the select before turning it into a selectize. In this instance, I need this option to stay, so I can't just get rid of that line of html. But I also can't add a "type" attribute to the option, or even a data-type attribute, it doesn't pass it along.
Finally I figured out from this discussion board:
Add data-attribute to selectize.js options
that I can assign a data-data attribute and pass it the name and value, and then it would pass that attribute along when it turns into a selectize. So my final solution was to add what I needed via the option before it turns into a selectize:
<option selected disabled value="default" data-data='{"type":"first"}'>The Stuff</option>
May this help some other poor soul from having to go through this in the future.

How to set target anchor when creating a link

I'm trying to set a specific anchor point when creating a link. I believe I'm doing everything correctly, but the anchor options are being ignored. In fact, any options I pass in are being ignored.
My code looks something like this:
new joint.shapes.standard.Link().target({id: 'xxx'}, {
anchor: {
name: 'center',
args: { dy: -15 }
}
});
The target id is being correctly handled, but whatever I pass in the second parameter is totally ignored.
Has anyone come across this before?
After experimenting, I worked out that when passing an object with id, rather than parsing a target element, that the opts need to go inside the object with the id. This is not documented AFAIK.
i.e.
.target({id: element.id, opts})
In my specific case, I'm passing the following:
.target({ id: to.id, anchor: { name: 'center', args: { dy: -15 }}})
This seems to work correctly

How to update the data in an ng2-chartjs2 chart in Angular 2 and Node JS

I am using NodeJS, Angular2, and the ng2-chartjs2. Below I listed the relevant parts of my code that is rendering charts. The data is loaded into this.data from an API using a fixed date range. I would like to allow the user to select a date range and then update the chart. From here I know that you can call update() on the chart object to update the data in it, but I don't know how to get a hold of the chart object, since the component code never actually has a reference to it - it's done automagically when the template is rendered. Looking at the source code (line 13) I see that the author intended to make the object available. I contacted the author but haven't received a response yet and need to get moving. I have learned a lot about Angular2 but am no expert yet, so perhaps a deeper understanding of Angular2 makes this obvious. How can I either get access to the object to call update() on it, or do it some other clean way?
The template contains
<chart [options]="simple.options"></chart>
and the component typescript code contains
import { ChartComponent } from 'ng2-chartjs2';
...
#Component({
selector: 'home',
templateUrl: 'client/components/home/home.component.html',
styleUrls: ['client/components/home/home.component.css'],
directives: [DashboardLayoutComponent, CORE_DIRECTIVES, ChartComponent],
pipes: [AddCommasPipe],
})
...
setCurrentSimpleChart = (simpleType: number): void => {
this.simple.options = {
type: 'line',
options: this.globalOptions,
data: {
labels: this.data[simpleType].labels,
datasets: [{
label: this.titles[simpleType],
data: this.data[simpleType].data,
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255,99,132,1)',
borderWidth: 1
}],
},
};
...
}
Update: In case this helps anyone: I actually have two different charts on the page, so I googled around based on the accepted answer and found ViewChildren, and mapped them to different variables so I can update them both separately, with
[this.simpleChart, this.liftChart] = this.chartComponents.toArray().map(component => component.chart);
(Note also that this was using an rc of angular2 - since then directives, etc have been moved out of the components themselves.)
You can hold reference to component by using ViewChild:
#ViewChild(ChartComponent) chartComp;
And then you can get chart object:
let chart = this.chartComp.chart;
Here is the corresponding plunker

Resources