I used Gridelements a while now. I used the following code:
TypoScript (Gridelements (deprecated) (gridelements)):
tt_content.gridelements_pi1.20.10.setup {
2col < lib.gridelements.defaultGridSetup
2col.cObject = FLUIDTEMPLATE
2col.cObject.file = {$resDir}/Private/Partials/Gridelements/2spalten.html
}
FLUID Template:
<div class="row">
<div class="col-md-6">
{data.tx_gridelements_view_column_0}
</div>
<div class="col-md-6">
{data.tx_gridelements_view_column_1}
</div>
</div>
PageTS:
tx_gridelements.setup {
2col {
title = Two Columns
config {
colCount = 2
rowCount = 1
rows {
1 {
columns {
1 {
name = Links
colPos = 0
}
2 {
name = Rechts
colPos = 1
}
}
}
}
}
}
}
But now I want to use "Gridelements w/DataProcessing (recommended) (gridelements)" because the other one is deprecated. But all I see is the error:
Tried resolving a template file for controller action "Standard->2col"
in format ".html", but none of the paths contained the expected
template file (Standard/2col.html). The following paths were checked:
/var/www/html/typo3/sysext/fluid_styled_content/Resources/Private/Templates/,
/var/www/html/typo3/typo3conf/ext/gridelements/Resources/Private/Templates/,
/var/www/html/typo3/typo3conf/ext/dev_layout/Resources/Private/Templates/
If I write this in my TypoScript code:
lib.gridelements.defaultGridSetup =< lib.contentElement
lib.gridelements.defaultGridSetup {
templateRootPaths {
20 = {$resDir}/Private/Templates/Gridelements/
}
}
tt_content.gridelements_pi1 < lib.gridelements.defaultGridSetup
tt_content.gridelements_view < tt_content.gridelements_pi1
And when I create the named file, the error no longer appears. But there is no output. I see the divs but no content. How can I switch from deprecated gridelements to dataprocessing gridelements?
"The documentation is wrong you need this"
tt_content.gridelements_pi1 =< lib.contentElement
Sure? I could still use the original as it is written in the example for w / DataProcessing:
lib.gridelements.defaultGridSetup =< lib.contentElement
The problem is that this code
tt_content.gridelements_pi1.20.10.setup {
2col < lib.gridelements.defaultGridSetup
2col.cObject = FLUIDTEMPLATE
2col.cObject.file = {$resDir}/Private/Partials/Gridelements/2spalten.html
}
does not match the new static you included.
Take a look at the basic example shown in the documentation:
https://docs.typo3.org/typo3cms/extensions/gridelements/stable/Chapters/DataProcessing/Index.html
lib.gridelements.defaultGridSetup =< lib.contentElement
lib.gridelements.defaultGridSetup {
templateName.field = tx_gridelements_backend_layout
templateName.ifEmpty = GridElement
layoutRootPaths {
1 = EXT:gridelements/Resources/Private/Layouts/
}
partialRootPaths {
1 = EXT:gridelements/Resources/Private/Partials/
}
templateRootPaths {
1 = EXT:gridelements/Resources/Private/Templates/
}
dataProcessing {
10 = GridElementsTeam\Gridelements\DataProcessing\GridChildrenProcessor
10 {
default {
as = children
# Default options of the grid children processor
# Change them according to the needs of your layout
# Read more about it in the TypoScript section of the manual
# options {
# sortingDirection = ASC
# sortingField = sorting
# recursive = 0
# resolveFlexFormData = 1
# resolveBackendLayout = 1
# respectColumns = 1
# respectRows = 1
# }
}
}
}
}
Now if you want to add your own templates and rendering configurations you just need to add something in dataProcessing.10 like
dataProcessing {
10 = GridElementsTeam\Gridelements\DataProcessing\GridChildrenProcessor
10 {
2col {
as = columncontent
options {
resolveFlexFormData = 0
respectRows = 0
}
}
accordion {
as = accordionitems
options {
resolveFlexFormData = 0
respectRows = 0
respectColumns = 0
}
}
}
}
The name of the variables can still be children, but it might be more comfortable to deal with variable names matching then purpose of your template.
I found the solution:
Template:
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
<div class="row">
<f:if condition="{children}">
<f:for each="{children.1}" as="column" key="columnNumber">
<div id="c{data.uid}-{columnNumber}" class="grid-column grid-column-{columnNumber} col-lg-6">
<f:for each="{column}" as="child">
<f:render partial="Child"
arguments="{data: child.data, children: child.children, options: options, settings: settings}" />
</f:for>
</div>
</f:for>
</f:if>
</div>
</html>
For two different cols
<div id="c{data.uid}-{columnNumber}" class="grid-column grid-column-{columnNumber} {f:if(condition: '{columnNumber} == 0', then: 'col-lg-3', else: 'col-lg-9')}">
My column numbers are left 0 and right 1
TS in dataprocessing.10:
2col {
as = children
options {
resolveChildFlexFormData = 0
}
}
}
The documentation is wrong you need this
tt_content.gridelements_pi1 =< lib.contentElement
TSconfig:
Default gridelements TSConfig
I got same error after i upgrade to latest TYPO3 10 version from Typo3 9 and include Gridelement (Recommended).
Tried resolving a template file for controller action "Standard->1" in format ".html", but none of the paths contained the expected template file (Standard/1.html). The following paths were checked:
Solution:
Rename gridelement template name with 1.html for gridelement uid=1
Change TS like:
tt_content.gridelements_pi1 {
templateRootPaths {
15 = EXT:site_config/Resources/Private/Templates/Extensions/Grid-Templates/
}
dataProcessing {
10 {
default {
options {
resolveFlexFormData = 1
resolveChildFlexFormData = 0
}
}
}
}
}
Inside Grid-Templates add your gridelement templates like 1.html, 2.html etc.
3) change template(HTML) code like this:
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
<div class="row">
<f:if condition="{children}">
<f:for each="{children.1}" as="column" key="columnNumber">
<div id="c{data.uid}-{columnNumber}" class="grid-column grid-column-{columnNumber} col-lg-6">
<f:for each="{column}" as="child">
<f:render partial="Child"
arguments="{data: child.data, children: child.children, options: options, settings: settings}" />
</f:for>
</div>
</f:for>
</f:if>
</div>
</html>
Related
Initially I had everything working with Chosen plugin when the options were directly passed from python to the html template.
I then tried to make the options filled dynamically depending on one of the buttons clicked, the options were not rendered so nothing showed up (but if I inspect the Elements, each optgroup was filled correctly with options).
And if I remove $(".chosen-select").chosen() , then the options are rendered.
Here's my code:
<!-- language: html -->
<div class="container" style="margin:auto; padding-top: 2%; text-align: center;">
<b>Choose the Program:</b>
<ul id="programs" class="no-bullets" data-tag="programList">
<li onclick="selectProgram(this)">Type1</li>
<li onclick="selectProgram(this)">Type2</li>
<li onclick="selectProgram(this)">Type3</li>
</ul>
<b>Choose the Documents:</b>
<select id="documentOptions" name="documents" data-placeholder="Your Documents" class="chosen-select" multiple>
<optgroup label="Group1" id="Group1"></optgroup>
<optgroup label="Group2" id="Group2"></optgroup>
<optgroup label="Group3" id="Group3"></optgroup>
</select>
</div>
<!-- language: lang-js -->
<script>
$(".chosen-select").chosen()
function selectProgram(el){
Array.prototype.slice.call(document.querySelectorAll('ul[data-tag="programList"] li')).forEach(function(element){
element.classList.remove('selected');
});
el.classList.add('selected');
programSelected = el.innerText;
//console.log(programSelected);
fetch(`/api/data/get_program/${programSelected}`)
.then(function(response){
return response.json();
}).then(function(documentList){
documentListJSON = {"documents":documentList};
//console.log(documentListJSON);
$.ajax({
type: 'POST',
url: '/api/data/programDocuments',
contentType: 'application/json',
data: JSON.stringify(documentListJSON),
success: function( allDocuments ){
console.log(allDocuments);
const Type1_Options = document.getElementById("Group1");
const Type2_Options = document.getElementById("Group2");
const Type3_Options = document.getElementById("Group3");
Type1_Options.innerHTML = "";
Type2_Options.innerHTML = "";
Type3_Options.innerHTML = "";
let docs_type1 = allDocuments['type1'];
let docs_type2 = allDocuments['type2'];
let docs_type3 = allDocuments['type3'];
// create list of options
var options = "";
for(var i = 0; i<docs_type1.length;i++){
options += "<option value='" + docs_type1[i] +"'>" + docs_type1[i] + "</option>";
}
Type1_Options.innerHTML += options;
$(Type1_Options).appendTo('#Group1');
var options = "";
for(var i = 0; i<docs_type2.length;i++){
options += "<option value='" + docs_type2[i] +"'>" + docs_type2[i] + "</option>";
}
Type2_Options.innerHTML += options;
$(Type2_Options).appendTo('#Group2');
var options = "";
for(var i = 0; i<docs_type3.length;i++){
options += "<option value='" + docs_type3[i] +"'>" + docs_type3[i] + "</option>";
}
Type3_Options.innerHTML += options;
$(Type3_Options).appendTo('#Group3');
}
})
})
}
</script>
I'm quite new to JavaScript and Jquery..Could someone please help explain why this happens?
Any help is very much appreciated. Thank you!
I've created a session list that contains my products, i need to update the quantity of any product by increasing it amount, for that am using an HTML type="number" , i also created a function which take the changed amount and multiplying it value with the current quantity, so lets say the amount of the first product by default is 2 by increasing the number lets say 2 the product amount will become 4 and so on, also the price will be multiplied .
Here are the codes:
<th style="text-align: center;" class="amount-izd">{{value["amount"]}}</th>
<th style="text-align: center; width: 14%;">
<div class="block">
<input type="number" id="myNumber" value="1" min=1 data-amount='{{value["amount"]}}' data-pros='{{value["id"]}}' data-price='
{% if g.currency == "euro" %}
{{format_price(value["price"] * config.SITE_CURRENCIES["euro"]).rsplit(".",1)[0]}}
{% elif g.currency == "dollar" %}
{{format_price(value["price"] * config.SITE_CURRENCIES["dollar"]).rsplit(".",1)[0]}}
{% else %}
{{format_price(value["price"] * config.SITE_CURRENCIES["ruble"]).rsplit(".",1)[0]}}
{% endif %}
'>
<label for="myNumber">qty</label>
</div>
</th>
JQuery codes:
$("input[type='number']").bind('keyup change click', function (e) {
if (! $(this).data("previousValue") ||
$(this).data("previousValue") != $(this).val()
)
{
var currentAmount = $(this).attr('data-amount');
var currentPrice = $(this).attr('data-price');
$(this).closest('tr').find('.amount-izd').text(parseInt(currentAmount) * $(this).val());
$(this).closest('tr').find('.price-izd').text(parseInt(currentPrice) * $(this).val());
$.ajax({
type: 'post',
url: '/standard-{{g.currency}}/profile/'+$(this).attr("data-pros")+'/update/price/' + parseInt(currentPrice) * $(this).val(),
cache: false
}).done(function(data){
if(data.error){
toastr.error(data.error)
}
});
$(this).data("previousValue", $(this).val());
} else {
}
});
And finally views.py :
#profile_route.route("/standard-<set_curr>/profile/cart/", methods=['GET','POST'])
#authorize
def cart_products():
if "cart" not in session:
return render_template("my-cart.html", display_cart = {}, total = 0)
else:
items = session["cart"]
dict_of_products = {}
total_price = 0
for item in items:
product = Goods.query.get(item)
total_price += product.price
if product.id in dict_of_products:
pass
else:
dict_of_products[product.id] = {"qty":1, "name":product.product_name, 'category':product.Category.name, "sizes": product.sizes, "hex_color":product.hex_color, "text_color":product.text_color, "material":product.material, "article":product.article, "price":product.price, "sort": product.sort, "amount": product.amount, 'slug':product.slug, 'public_id' : product.public_id, "id":product.id}
return render_template("my-cart.html", display_cart=dict_of_products, total = total_price)
#profile_route.route("/standard-<set_curr>/profile/<int:id>/update/price/<price>", methods=['GET','POST'])
#login_required
def update_price(id, price):
items = session["cart"]
dict_of_products = {}
for item in items:
product = Goods.query.get(item)
if product.id in dict_of_products:
dict_of_products[id]['price'] = price
return jsonify(success=dict_of_products[id]['price'])
return jsonify(error='No product found.')
If i changed the amount , in console i got a 500 error that says:
return jsonify(success=dict_of_products[id]['price'])
KeyError: 47
Please how to overcome this problem ?
Update:
I was wondering , is it possible to update any value of the dictionary by accessing it directly from JQuery ??
I have an HMENU with a submenu and I want to add a third submenu, if the main menu point has the uid xxx.
If I implement this TypoScript Code, all third submenus will be shown:
3 = TMENU
3 {
stdWrap.outerWrap = <div class="submenu-third-level"><ul class='submenu'>|</ul></div>
stdWrap.outerWrap.override = <div class="submenu-third-level show"><ul class='submenu'>|</ul></div>
stdWrap.outerWrap.override.if {
value.data = field:pid
isInList = 588
}
stdWrap.insertData = 1
NO.wrapItemAndSub = <li class="menu-item">|</li>
ACT = 1
ACT{
wrapItemAndSub = <li class="menu-item active">|</li>
}
SPC = 1
SPC {
doNotLinkIt = 1
doNotShowLink = 1
allWrap = </ul><ul class='submenu'>
}
}
Thus, all submenus of submenus will be shown. But I want to only show the submenus of submenus in HMENU PID XXX.
Is there a possibility to do it like:
3 = TMENU
3 {
stdWrap.outerWrap = <div class="submenu-third-level"><ul class='submenu'>|</ul></div>
stdWrap.outerWrap.override = <div class="submenu-third-level show"><ul class='submenu'>|</ul></div>
stdWrap.outerWrap.override.if {
value.data = field:pid
isInList = 588
}
stdWrap.insertData = 1
NO.wrapItemAndSub = <li class="menu-item">|</li>
ACT = 1
ACT{
wrapItemAndSub = <li class="menu-item active">|</li>
}
SPC = 1
SPC {
doNotLinkIt = 1
doNotShowLink = 1
allWrap = </ul><ul class='submenu'>
}
if {
value.data = field:pid
equals = xxx
}
}
Look you better use new HMENU like:
lib.mainmenu = HMENU
...{
1 = TMENU
...
2 = TMENU
} # so just two levels
lib.tempmenu <. lib.mainmenu # just save your menu
[PIDinRootline = xxx]
#or [globalVar = TSFE:id=xxx]
lib.mainmenu <. lib.tempmenu
lib.mainmenu.3 = TMENU # just add 3d submenu. Prev menu haven't it
[global]
If not, please leave comment
thanks for your response. I solved in a different way and it works great.
My solution:
3 = TMENU
3 {
stdWrap.outerWrap = <div class="submenu-third-level"><ul class='submenu'>|</ul></div>
stdWrap.if {
value.data = field:pid
isInList = {$menu.thirdSubmenuList}
}
NO.wrapItemAndSub = <li class="menu-item">|</li>
ACT = 1
ACT{
wrapItemAndSub = <li class="menu-item active">|</li>
}
SPC = 1
SPC {
doNotLinkIt = 1
doNotShowLink = 1
allWrap = </ul><ul class='submenu'>
}
}
The condition decide, if the menu will be displayed or not.
best regards
I would like to combine two menu's into one for mobile. So with the foundation top-bar the standaard menu is shown and the below the tip menu into one menu. But i don't get the tip menu wrapped into the main menu just before the first . See code below, any idee?
topnavigation = HMENU
topnavigation.wrap (
<section class="topnavigation">
<div class="row">
<div class="columns large-12">
<nav class="top-bar" data-topbar data-options="back_text: « Vorige">
<ul class="title-area">
<li class="name">
<h1></h1>
</li>
<li class="toggle-catmenu show-for-small menu-icon">Tips</li>
<li class="toggle-topbar menu-icon"><span>Menu</span></li>
</ul>
<section class="top-bar-section">
<ul class="right">|<li class="divider"></li></ul>
</section>
</nav>
</div>
</div>
</section>
)
topnavigation.entryLevel = 0
topnavigation {
1= TMENU
1 {
expAll = 1
maxItems = 4
NO.wrapItemAndSub = <li class="top-but">|</li>
ACT = 1
ACT.wrapItemAndSub = <li class="active top-but">|</li>
IFSUB = 1
IFSUB.wrapItemAndSub = <li class="has-dropdown top-but">|</li>
ACTIFSUB = 1
ACTIFSUB.wrapItemAndSub= <li class="active has-dropdown top-but">|</li>
}
2= TMENU
2 {
wrap = <ul class="dropdown">|</ul>
NO.wrapItemAndSub = <li>|</li>
ACT = 1
ACT.wrapItemAndSub = <li class="active">|</li>
}
}
tipmenu = HMENU
tipmenu.special = directory
tipmenu.special.value = 8
tipmenu.allWrap = <ul class="left">|</ul>
tipmenu {
1 = TMENU
1 {
expAll = 1
maxItems = 4
NO.wrapItemAndSub = <li class="top-but">|</li>
ACT = 1
ACT.wrapItemAndSub = <li class="active top-but">|</li>
IFSUB = 1
IFSUB.wrapItemAndSub = <li class="has-dropdown top-but">|</li>
ACTIFSUB = 1
ACTIFSUB.wrapItemAndSub= <li class="active has-dropdown top-but">|</li>
}
2= TMENU
2 {
wrap = <ul class="dropdown">|</ul>
NO.wrapItemAndSub = <li>|</li>
ACT = 1
ACT.wrapItemAndSub = <li class="active">|</li>
}
}
You can't combine one HMENU inside the other instead you need to use COA cObject, COA allows for combining many cObjects (even different type):
myCombinedMenu = COA
myCombinedMenu.10 < lib.mainMenu
myCombinedMenu.20 < lib.additionalMenu
myCombinedMenu.30 = TEXT
myCombinedMenu.30.value = ...and that's it...
This should do it. COA is not necessary. This solution has a common parent ul tag and displays both sub tree items (the items of two different sub-trees) at the same ul level:
temp.mainMenuObject = HMENU
temp.mainMenuObject {
# entryLevel = 1
special = directory
special.value = pid1, pid2 # pids of parent pages
1 = TMENU
1 {
expAll = 1
wrap = <ul> | </ul>
NO = 1
NO {
wrapItemAndSub = <li>|</li>
ATagTitle.field = title
}
}
2 < .1
}
I'm trying to modify a template in TYPO3 and I can modify some parts of the page, but not some other parts that are 1 level deeper. For example :
HTML
<body>
...
<div class="wrapper">
...
<div id="content-right">
<div id="colRight">
<div id="metaNav"></div>
</div>
</div>
...
</div>
...
</body>
Typoscript
page.10.subparts {
colRight = HMENU
colRight.wrap = <ul>|</ul>
colRight.special.value = 6, 7, 8, 9
colRight.1 = TMENU
colRight.1 {
noBlur = 1
NO = 1
NO {
allWrap = <li>|</li>
}
}
}
But if I change colRight with metaNav (because this is where we want the links so we can place other contents in colRight), nothing happens; no content is displayed. Why?
While you have it mapped to #colRight and have problem with mapping it to its child div you can just add a HTML markup to element's wrap:
page.10.subparts {
colRight = HMENU
colRight.wrap = <div id="metaNav"><ul>|</ul></div>
// etc...
}
With rule #1: In TS every way is the best solution to get immediate results :)
edit
if you need to render many different elements under one HTML tag, you can also use COA element to span them:
page.10.subparts {
colRight = COA
colRight {
10 = HMENU
10 {
wrap = <div id="metaNav"><ul>|</ul></div>
// etc...
}
20 = TEXT
20 {
value = my text in #colRight right after #metaNav
wrap = <div class="containerAfterMetsNav">|</div>
}
}
}