Neos CMS error when placing content to page - fusion

recently in Neos CMS, I got this error when i used content element in page.
An exception was thrown while Neos tried to render your page
The Fusion object `Company.Corp:Content.ContactUsPage` cannot be rendered: Most likely you
mistyped the prototype name or did not define the Fusion prototype with
`prototype(Company.Corp:Content.ContactUsPage) < prototype ...` . Other possible reasons are a
missing parent-prototype or a missing `#class` annotation for prototypes without parent. It is
also possible your Fusion file is not read because of a missing `include:` statement.
But I think my Node and Fusion file are correct without any mistake. But maybe Im wrong. Could you please help me with solve this error? Im beginner in this.
Here is my code from Node file called NodeTypes.Content.ContactUsPage.yaml:
'Company.Corp:Content.ContactUsPage':
superTypes:
'Neos.Neos:Content': true
ui:
label: 'Contact Us Page'
icon: icon-file-text
inlineEditable: true
inspector:
groups:
showCases:
label: 'Contact Us Page Data'
icon: icon-file-text
position: 5
properties:
smallTitle:
type: string
defaultValue: ''
ui:
label: 'Small Title'
inspector:
group: 'contactUsPage'
editorOptions:
placeholder: ''
maxlength: 300
And here is my fusion file called ContactUsPage.fusion:
prototype(Company.Corp:Content.ContactUsPage) < prototype(Neos.Neos:ContentComponent) {
smallTitle = Neos.Neos:Editable {
property = 'smallTitle'
}
renderer = afx`
<div id="contact" class="row mt-5">
<div class="col-lg-6">
<div class="contact-caption">
<div class="section-title mt-5">
<div class="upTitle">{props.smallTitle}</div>
</div>
</div>
</div>
</div>
`
}

re-name your Fusion file to "Content.ContactUsPage.fusion" and you should be fine.
OR
Alternatively, you could re-write line1 in your .yaml to:
Company.Corp:ContactUsPage':
both should work
The naming of the fusion file needs to be equivalent to the first line in your yaml. if you go for "Content.foo" your Fusion needs to be named "Content.Foo.fusion" as well.
hope that helps

Related

A way to render multiple root elements on VueJS with v-for directive

Right now, I'm trying to make a website that shows recent news posts which is supplied my NodeJS API.
I've tried the following:
HTML
<div id="news" class="media" v-for="item in posts">
<div>
<h4 class="media-heading">{{item.title}}</h4>
<p>{{item.msg}}</p>
</div>
</div>
JavaScript
const news = new Vue({
el: '#news',
data: {
posts: [
{title: 'My First News post', msg: 'This is your fist news!'},
{title: 'Cakes are great food', msg: 'Yummy Yummy Yummy'},
{title: 'How to learnVueJS', msg: 'Start Learning!'},
]
}
})
Apparently, the above didn't work because Vue can't render multiple root elements.
I've looked up the VueJS's official manual and couldn't come up with a solution.
After googling a while, I've understood that it was impossible to render multiple root element, however, I yet to have been able to come up with a solution.
The simplest way I've found of adding multiple root elements is to add a single <div> wrapper element and make it disappear with some CSS magic for the purposes of rendering.
For this we can use the "display: contents" CSS property. The effect is that it makes the container disappear, making the child elements children of the element the next level up in the DOM.
Therefore, in your Vue component template you can have something like this:
<template>
<div style="display: contents"> <!-- my wrapper div is rendered invisible -->
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
</div>
</template>
I can now use my component without the browser messing up formatting because the wrapping <div> root element will be ignored by the browser for display purposes:
<table>
<my-component></my-component> <!-- the wrapping div will be ignored -->
</table>
Note however, that although this should work in most browsers, you may want to check here to make sure it can handle your target browser.
You can have multiple root elements (or components) using render functions
A simple example is having a component which renders multiple <li> elements:
<template>
<li>Item</li>
<li>Item2</li>
... etc
</template>
However the above will throw an error. To solve this error the above template can be converted to:
export default {
functional: true,
render(createElement) {
return [
createElement('li', 'Item'),
createElement('li', 'Item2'),
]
}
}
But again as you probably noticed this can get very tedious if for example you want to display 50 li items. So, eventually, to dynamically display elements you can do:
export default {
functional: true,
props: ['listItems'], //this is an array of `<li>` names (e.g. ['Item', 'Item2'])
render(createElement, { props }) {
return props.listItems.map(name => {
return createElement('li', name)
})
}
}
INFO in those examples i have used the property functional: true but it is not required of course to use "render functions". Please consider learning more about functional componentshere
Define a custom directive:
Vue.directive('fragments', {
inserted: function(el) {
const children = Array.from(el.children)
const parent = el.parentElement
children.forEach((item) => { parent.appendChild(item) })
parent.removeChild(el)
}
});
then you can use it in root element of a component
<div v-fragments>
<tr v-for="post in posts">...</tr>
</div>
The root element will not be rendered in DOM, which is especially effective when rendering table.
Vue requires that there be a single root node. However, try changing your html to this:
<div id="news" >
<div class="media" v-for="item in posts">
<h4 class="media-heading">{{item.title}}</h4>
<p>{{item.msg}}</p>
</div>
</div>
This change allows for a single root node id="news" and yet still allows for rendering the lists of recent posts.
In Vue 3, this is supported as you were trying:
In 3.x, components now can have multiple root nodes! However, this does require developers to explicitly define where attributes should be distributed.
<!-- Layout.vue -->
<template>
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
</template>
Multiple root elements are not supported by Vue (which caused by your v-for directive, beacause it may render more than 1 elements). And is also very simple to solve, just wrap your HTML into another Element will do.
For example:
<div id="app">
<!-- your HTML code -->
</div>
and the js:
var app = new Vue({
el: '#app', // it must be a single root!
// ...
})

Reveal.js presentation full screen from JHipster

I am trying to show a reveal.js presentation full screen from a JHipster single page app. The reveal.js example below works fine inside JHipster, it's just not full screen. It can be made full screen by creating a second page, but given JHipster's design as a single page app things get messy with grunt and the production profile. I've also tried hiding the app menu bar and footer div elements but the reveal presentation still has padding around it. Ideally a full-screen view can configured.
Simple Reveal slide
<div ng-cloak>
<div class="reveal">
<div class="slides">
<section data-background="#faebd7">
<h1>FULL SCREEN SLIDE</h1>
</section>
</div>
</div>
</div>
A second page is the way to go and below is a way to by-pass optimizations made by JHipster's production build.
JHipster's production build only optimizes files under src/main/webapp/scripts and src/main/webapp/assets directories. So, put your presentation files including revealjs under another folder (e.g. src/main/webapp/slides) and use a simple link from your app to load the presentation.
This is what is done for swagger-ui under src/main/webapp/swagger-ui
I solved the problem while keeping it a single page app. Previously I tried hiding elements of the page that prevented full-screen, but padding on the main div container was preventing full screen. The solution was to create a second ui-view div designed for full screen and hide all other div elements.
Solution:
1. Add "hidewhenfullscreen" class to the elements to hide.
2. Use javascript to show/hide elements
3. Add a second fullpage ui-view designed for full screen
4. Reference the fullpage ui-view from the controller
index.html
<div ng-show="{{ENV === 'dev'}}" class="development hidewhenfullscreen" ng-cloak=""></div>
<div ui-view="navbar" ng-cloak="" class="hidewhenfullscreen"></div>
<div class="container hidewhenfullscreen">
<div class="well" ui-view="content"></div>
<div class="footer">
<p translate="footer">This is your footer</p>
</div>
</div>
JavaScript to show/hide elements
<script>
hide(document.querySelectorAll('.hidewhenfullscreen'));
function hide (elements) {
elements = elements.length ? elements : [elements];
for (var index = 0; index < elements.length; index++) {
elements[index].style.display = 'none';
}
}
function show (elements) {
elements = elements.length ? elements : [elements];
for (var index = 0; index < elements.length; index++) {
elements[index].style.display = 'block';
}
}
</script>
JavaScript controller
.state('show', {
parent: '',
url: '/show/{presentationName}',
data: {
authorities: [], // none, wide open
pageTitle: 'page title'
},
views: {
'fullpage#': {
templateUrl: 'scripts/show/show.html',
controller: 'ShowController'
}
}
})
The page has a single small "Home" href that calls the show function. This way the user can go back and forth between the full-screen Reveal presentation and the standard jHipster view.
show.html
<div ng-show="{{ENV === 'dev'}}" class="development"></div>
<div class="miniMenu" id="miniMenu" ng-cloak="">
Home
</div>
<div class="reveal">
<div class="slides">
<section data-background={{getBackgroundURI($index)}} ng-repeat="slide in slides track by $index">
<div ng-bind-html="getContent($index)"></div>
</section>
</div>
</div>
For completeness, creating a second page can work but I don't think it is worth the added complexity. A two-page solution worked fine in the development profile, but the production profile had issues with caching shared css files, js files and fonts. With time and energy, I am sure the proper grunt configuration can be made to work, although the idea seems to counter the single page design concept. While in Rome, do as the Romans do.

Nested ListView or Nested Repeater

I am trying to created a nested repeater or a nested list view using WinJS 4.0, but I am unable to figure out how to bind the data source of the inner listview/repeater.
Here is a sample of what I am trying to do (note that the control could be Repeater, which I would prefer):
HTML:
<div id="myList" data-win-control="WinJS.UI.ListView">
<span data-win-bind="innerText: title"></span>
<div data-win-control="WinJS.UI.ListView">
<span data-win-bind="innerText: name"></span>
</div>
</div>
JS:
var myList = element.querySelector('#myList).winControl;
var myData = [
{
title: "line 1",
items: [
{name: "item 1.1"},
{name: "item 1.2"}
]
},
{
title: "line 2",
items: [
{name: "item 2.1"},
{name: "item 2.2"}
]
}
];
myList.data = new WinJS.Binding.List(myData);
When I try this, nothing renders for the inner list. I have attempted trying to use this answer Nested Repeaters Using Table Tags and this one WinJS: Nested ListViews but I still seem to have the same problem and was hoping it was a little less complicated (like KnockOut).
I know it is mentioned that WinJS doesn't support nested ListViews, but that seems to be a few years ago and I am hoping that is still not the issue.
Update
I was able to get the nested repeater to work correctly, thanks to Kraig's answer. Here is what my code looks like:
HTML:
<div id="myTemplate" data-win-control="WinJS.Binding.Template">
<div
<span>Bucket:</span><span data-win-bind="innerText: name"></span>
<span>Amount:</span><input type="text" data-win-bind="value: amount" />
<button class="removeBucket">X</button>
<div id="bucketItems" data-win-control="WinJS.UI.Repeater"
data-win-options="{template: select('#myTemplate')}"
data-win-bind="winControl.data: lineItems">
</div>
</div>
</div>
<div id="budgetBuckets" data-win-control="WinJS.UI.Repeater"
data-win-options="{data: Data.buckets,template: select('#myTemplate')}">
</div>
JS: (after the "use strict" statement)
WinJS.Namespace.define("Data", {
buckets: new WinJS.Binding.List([
{
name: "A",
amount: 5,
lineItems: new WinJS.Binding.List( [
{ name: 'test item1', amount: 50 },
{ name: 'test item2', amount: 25 }
]
)
}
])
})
*Note that this answers part of my question, however, I would really like to do this all after a repo call and set the repeater data source programmatically. I am going to keep working towards that and if I get it I will post that as the accepted answer.
The HTML Repeater control sample for Windows 8.1 has an example in scenario 6 with a nested Repeater, and in this case the Repeater is created through a Template control. That's a good place to start. (I discuss this sample in Chapter 7 of Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition, starting on page 372, or 374 for the nested part.)
Should still work with WinJS 4, though I haven't tried it.
Ok, so I have to give much credit to Kraig because he got me on the correct path to getting this worked out and the referenced book Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition is amazing.
The original issue was a combination of not using templates correctly (using curly braces in the data-win-bind attribute), not structuring my HTML correctly and not setting the child lists as WinJS.Binding.List data source. Below is the final working code structure to created a nested repeater when binding the data from code only:
HTML:
This is the template for the child lists. It looks similar, but I plan on add more things so I wanted it separate instead of recursive as referenced in the book. Note that the inner div after the template control declaration was important for me.
<div id="bucketItemTemplate" data-win-control="WinJS.Binding.Template">
<div>
<span>Description:</span>
<span data-win-bind="innerText: description"></span>
<span>Amount:</span>
<input type="text" data-win-bind="value: amount" />
<button class="removeBucketItem">X</button>
</div>
</div>
This is the main repeater template for the lists. Note that the inner div after the template control declaration was important for me. Another key point was using the "winControl.data" property against the property name of the child lists.
<div id="bucketTemplate" data-win-control="WinJS.Binding.Template">
<div>
<span>Bucket:</span>
<span data-win-bind="innerText: bucket"></span>
<span>Amount:</span>
<input type="text" data-win-bind="value: amount" />
<button class="removeBucket">X</button>
<div id="bucketItems" data-win-control="WinJS.UI.Repeater"
data-win-options="{template: select('#bucketItemTemplate')}"
data-win-bind="winControl.data: lineItems">
</div>
</div>
</div>
This is the main control element for the nested repeater and it is pretty basic.
<div id="budgetBuckets" data-win-control="WinJS.UI.Repeater"
data-win-options="{template: select('#bucketTemplate')}">
</div>
JavaScript:
The JavaScript came down to a few simple steps:
Getting the winControl
var bucketsControl = element.querySelector('#budgetBuckets').winControl;
Looping through the elements and making the child lists into Binding Lists - the data here is made up but could have easily came from the repo:
var bucketsData = selectedBudget.buckets;
for (var i = 0; i < bucketsData.length; i++) {
bucketsData[i].lineItems =
new WinJS.Binding.List([{ description: i, amount: i * 10 }]);
}
Then finally converting the entire data into a Binding list and setting it to the "data" property of the winControl.
bucketsControl.data = new WinJS.Binding.List(bucketsData);
*Note that this is the entire JavaScript file, for clarity.
(function () {
"use strict";
var nav = WinJS.Navigation;
WinJS.UI.Pages.define("/pages/budget/budget.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
// TODO: Initialize the page here.
var bindableBuckets;
require(['repository'], function (repo) {
//we can setup our save button here
var appBar = document.getElementById('appBarBudget').winControl;
appBar.getCommandById('cmdSave').addEventListener('click', function () {
//do save work
}, false);
repo.getBudgets(nav.state.budgetSelectedIndex).done(function (selectedBudget) {
var budgetContainer = element.querySelector('#budgetContainer');
WinJS.Binding.processAll(budgetContainer, selectedBudget);
var bucketsControl = element.querySelector('#budgetBuckets').winControl;
var bucketsData = selectedBudget.buckets;
for (var i = 0; i < bucketsData.length; i++)
{
bucketsData[i].lineItems = new WinJS.Binding.List([{ description: i, amount: i * 10 }]);
}
bucketsControl.data = new WinJS.Binding.List(bucketsData);
});
});
WinJS.UI.processAll();
}
});
})();

$scope.$apply and ng-include

I'm using a $scope.$apply to trigger the view to update based on a changed variable in the scope. However, I have another line in the html that is an ng-include,
<div data-ng-include data-ng-src="'views/partials/_menubar.html'"></div>
error message
When I remove the ng-include and replace it with a static call there is no error. Here is the template that I'm including as well:
<div class="menu" ng-controller="MenuController">
<div style="display: inline-block">
Hello!
</div>
<ul class="menu_dropdown">
<li class="menu_item">Test1</li>
<li class="menu_item">Test2</li>
<li class="menu_item">Test3</li>
</ul>
</div>
The code for menu controller is
app.controller('MenuController', function($scope) {
});
ng-src is used to allow elements that usually have a src (like anchors or images) to apply the src tag only after angular's digest, not for inclusion of templates in ng-include. See ng-include docs and ng-src docs.
A safe way to specify the src using ng-include would be like this:
<div data-ng-include="src='views/partials/_menubar.html'"></div>
or
<div data-ng-include="'views/partials/_menubar.html'"></div>
If you must have the src separately, it's data-src and not data-ng-src:
<div data-ng-include data-src="'views/partials/_menubar.html'"></div>
see plnkr.
edit: To address your error message.. you'll see that message if you've bound a function to the scope which changes every time it is called.
For example, this will cause such an error:
// controller
$scope.getQuote = function(){
return 'someViewName' + Math.ceil(Math.random() * 10) + '.html';
};
// view
<div data-ng-include="{{getQuote}}"></div>
The problem with ng-include was actually a red herring. The real problem was trying to change the window.history, as seen in the thread here. My guess is because the ng-include directive references $location when it attempts to get resources.

dojo layout tutorial for version 1.7 doesn't work for 1.7.2

This is sortof a continuation to dojo1.7 layout acting screwy.
So I made some working widgets and tested them out, i then tried altering my work using the tutorial at http://dojotoolkit.org/documentation/tutorials/1.7/dijit_layout/ to make the layout nice. After failing at that in many interesting ways (thus my last question) I started on a new path. My plan is now to implement the layout tutorial example and then stick in my widgets. For some reason even following the tutorial wont work... everything loads then disappears and I'm left with a blank browser window.
Any ideas?
It just struck me that it could be browser compatibility issues, I'm working on Firefox 13.0.1. As far as I know Dojo is supposed to be compatible with this...
anyway, have some code:
HTML:
<body class="claro">
<div
id="appLayout" class="demoLayout"
data-dojo-type="dijit.layout.BorderContainer"
data-dojo-props="design: 'headline'">
<div
class="centerPanel"
data-dojo-type="dijit.layout.ContentPane"
data-dojo-props="region: 'center'">
<div>
<h4>Group 1 Content</h4>
<p>stuff</p>
</div>
<div>
<h4>Group 2 Content</h4>
</div>
<div>
<h4>Group 3 Content</h4>
</div>
</div>
<div
class="edgePanel"
data-dojo-type="dijit.layout.ContentPane"
data-dojo-props="region: 'top'">
Header content (top)
</div>
<div
id="leftCol" class="edgePanel"
data-dojo-type="dijit.layout.ContentPane"
data-dojo-props="region: 'left', splitter: true">
Sidebar content (left)
</div>
</div>
</body>
Dojo Configuration:
var dojoConfig = {
baseUrl: "${request.static_url('mega:static/js')}", //this is in a mako template
tlmSiblingOfDojo: false,
packages: [
{ name: "dojo", location: "libs/dojo" },
{ name: "dijit", location: "libs/dijit" },
{ name: "dojox", location: "libs/dojox" },
],
parseOnLoad: true,
has: {
"dojo-firebug": true,
"dojo-debug-messages": true
},
async: true
};
other js stuff:
require(["dijit/layout/BorderContainer", "dijit/layout/TabContainer",
"dijit/layout/ContentPane", "dojo/parser"]);
css:
html, body {
height: 100%;
margin: 0;
overflow: hidden;
padding: 0;
}
#appLayout {
height: 100%;
}
#leftCol {
width: 14em;
}
I would suggest viewing the 'complete demo' on the tutorial page and then use firebug to compare your code to the example. Often they'll leave out an additional 'demo.css' file or something else that you actually need to stitch everything together.

Resources