I have a collection (categories) and each document has a "product" field that is an array of objects (products). Each product has a "name" and a "startingCost" field. I can display each category name, but I don't know how to display every product name inside every category.
HTML:
<template name='categoriesList'>
<ul class='category-grid'>
{{ #each categories }}
<li>{{ name }}</li>
<!-- Display every product's name -->
{{/each}}
</ul>
</template>
JS:
Template.categoriesList.helpers({
categories() {
return Categories.find({});
},
});
Schema:
{
"_id" : "test",
"name" : "TestNAME",
"createdAt" : ISODate("2017-08-08T18:03:09.508Z"),
"products" : [
{ "name" : "testProduct", "startingCost" : 100 },
{ "name" : "test2", "startingCost" : 200 }
]
}
Should just be able to do another {{ #each }}
<template name='categoriesList'>
<ul class='category-grid'>
{{ #each category in categories }}
<li>{{ category.name }}</li>
<!-- Display every product's name -->
<ul>
{{ #each product in category.products }}
<li>{{ product.name }}: ${{ product.startingCost }}</li>
{{/each}}
</ul>
{{/each}}
</ul>
</template>
Up to you if you prefer the each products or each product in products syntax. When nesting I definitely prefer the namespaced one.
Related
I have posts in my 11ty blog - books, whose names started on some letters. For example, i have 12 books: 4 with first letter "A", 4 with first letter "F", 4 with first letter "Q".
And I have a code for printing all books (I use njk in blog layouts):
<div>
{% for book in collections.books %}
<a class="book" href="{{ book.url }}">
<article>
<h3 class="text-link">
{{ book.data.name }}
</h3>
<p>{{ book.data.text }}</p>
</article>
</a>
{% endif %}
{% endfor %}
</div>
I need to print in front of all books with the letter "A":
<h2>A</h2>
Аfter that there will be 4 books with the letter "A". And after this books, will be the same heading, but with letter "F":
<h2>F</h2>
How to do it? In njk, it is difficult to assign/rewrite and manipulate variables. Maybe there is some normal example?
You can use Nunjucks's set tag to create and modify a variable that keeps track of the previous initial letter:
<div>
{% set previousInitial = null %}
{% for book in collections.books %}
{% if book.data.name[0] != previousInitial %}
<h2>{{ book.data.name[0] }}</h2>
{% endif %}
{% set previousInitial = book.data.name[0] %}
<a class="book" href="{{ book.url }}">
<article>
<h3 class="text-link">
{{ book.data.name }}
</h3>
<p>{{ book.data.text }}</p>
</article>
</a>
{% endfor %}
</div>
Demo:
const data = {
collections: {
books: [
{ data: { name: 'ABC Book', text: 'Learn the alphabets!' }, url: '/book/abc-book/' },
{ data: { name: 'Another A book', text: 'A nice book' }, url: '/book/another-a-book/' },
{ data: { name: 'Foo...', text: '...bar and baz' }, url: '/book/foo/' },
],
},
}
const template = `
<div>
{% set previousInitial = null %}
{% for book in collections.books %}
{% if book.data.name[0] != previousInitial %}
<h2>{{ book.data.name[0] }}</h2>
{% endif %}
{% set previousInitial = book.data.name[0] %}
<a class="book" href="{{ book.url }}">
<article>
<h3 class="text-link">
{{ book.data.name }}
</h3>
<p>{{ book.data.text }}</p>
</article>
</a>
{% endfor %}
</div>
`
console.log(nunjucks.renderString(template, data))
.as-console-wrapper { max-height: 100% !important; }
<script src="https://unpkg.com/nunjucks#3.2.3/browser/nunjucks.min.js"></script>
If the items in collections.books are not already sorted by their names, you can sort them with Nunjucks's sort filter:
{% for book in collections.books|sort(attribute='data.name') %}
An alternative is to create a new collection. Consider creating a collection of books already categorized by their initial letters, so you can reduce the amount of logic in your Nunjucks template. Example of how the new collection and template could look like:
const data = {
collections: {
booksCategorizedByInitialLetters: {
A: [
{ data: { name: 'ABC Book', text: 'Learn the alphabets!' }, url: '/book/abc-book/' },
{ data: { name: 'Another A book', text: 'A nice book' }, url: '/book/another-a-book/' },
],
F: [
{ data: { name: 'Foo...', text: '...bar and baz' }, url: '/book/foo/' },
],
},
},
}
const template = `
<div>
{% for initialLetter, books in collections.booksCategorizedByInitialLetters %}
<h2>{{ initialLetter }}</h2>
{% for book in books %}
<a class="book" href="{{ book.url }}">
<article>
<h3 class="text-link">
{{ book.data.name }}
</h3>
<p>{{ book.data.text }}</p>
</article>
</a>
{% endfor %}
{% endfor %}
</div>
`
console.log(nunjucks.renderString(template, data))
.as-console-wrapper { max-height: 100% !important; }
<script src="https://unpkg.com/nunjucks#3.2.3/browser/nunjucks.min.js"></script>
(I'm not sure whether it's possible to create a collection whose type is an object, but IIRC it should be possible.)
My twig file looks like this:
<select name="lineItems[{{ product.id }}][quantity]"
class="custom-select product-detail-quantity-select">
{% for quantity in range(product.minPurchase, product.calculatedMaxPurchase, product.purchaseSteps) %}
<option value="{{ quantity }}">
{{ quantity }}{% if product.packUnit %} {{ product.packUnit }}{% endif %}
</option>
{% endfor %}
</select>
I want to change this into a Vue.js app with a quantity/count field and an 'increment' and 'decrement' button.
My Vue.js app looks like this:
<div id="app">
<a class="btn" v-on:click="increment">Add 1</a>
<a class="btn" v-on:click="decrement">Remove 1</a>
<span>[[ count ]]</span>
</div>
<script>
const App = new Vue({
el: '#app',
delimiters: ['[[',']]'],
data() {
return {
count: 1
}
},
methods: {
increment() {
this.count++
},
decrement() {
this.count--
}
}
})
</script>
If you look at my twig file, you see for example the twig variable {{ quantity }}.
How do I use this twig variable in my Vue.js app? So when the user increment the <span>[[ count ]]</span> value by 3. It add's 3 to the {{ quantity }} variable?
Shopware is not using twig. It is using twig.js for the block system. E.g. for overwriting certain parts in the templates. The logic have to be implemented in the vue component. Please descibe your full problem for more information.
I am getting Twig_Error_Runtime
I am trying to find the mistake I've made, but I can't see any... maybe I am looking at the wrong file, but I've tried looking everywhere I've done changes before this error appeared.
This is my twig code:
{% extends 'base.html.twig' %}
{% block body %}
<div class="container">
{% form_theme form 'bootstrap_4_layout.html.twig' %}
{{ form_start(form) }}
<br>
Name {{ form_widget(form.name) }}
Price {{ form_widget(form.price) }}
Available {{ form_widget(form.available) }}
Date {{ form_widget(form.date) }}
<div class="row js-ticket-time-wrapper"
data-prototype="{{ form_widget(form.times.vars.prototype)|e('html_attr') }}"
data-index="{{ form.times|length }}">
{% for time in form.times %}
<div class="col-xs-4 js-ticket-time-item">
<a href="#" class="js-remove-time pull-right">
<span class="fa fa-close"></span>
</a>
{{ form_row(time.name) }}
</div>
{% endfor %}
<a href="#" class="js-ticket-time-add">
<span class="fa fa-plus-circle"></span>
Add another Time
</a>
</div>
<button type="submit" class="btn btn-primary" formnovalidate>Save</button>
{{ form_end(form) }}
</div>
{% endblock %}
{% block js %}
{{ parent() }}
<script>
jQuery(document).ready(function() {
var $wrapper = $('.js-ticket-time-wrapper');
$wrapper.on('click', '.js-remove-time', function(e) {
e.preventDefault();
$(this).closest('.js-ticket-time-item')
.fadeOut()
.remove();
});
$wrapper.on('click', '.js-ticket-time-add', function(e) {
e.preventDefault();
// Get the data-prototype explained earlier
var prototype = $wrapper.data('prototype');
// get the new index
var index = $wrapper.data('index');
// Replace '__name__' in the prototype's HTML to
// instead be a number based on how many items we have
var newForm = prototype.replace(/__name__/g, index);
// increase the index with one for the next item
$wrapper.data('index', index + 1);
// Display the form in the page before the "new" link
$(this).before(newForm);
});
});
</script>
{% endblock %}
I've also made changes in Entities Time & Ticket, but I don't think so this is connected somehow.
Here's my TicketType Form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name',TextType::class)
->add('price',MoneyType::class)
->add('available',IntegerType::class)
->add('date',DateType::class)
->add('times', CollectionType::class, array(
'entry_type' => \App\Form\TimeType::class,
'allow_delete' => true,
'by_reference' => false,
'allow_add' => true,
));
}
And this is TimeType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', TextType::class);
}
Because the classname of your formtype TimeType is the same as the Symfony TimeType (https://symfony.com/doc/current/reference/forms/types/time.html) the formtheme layout tries to render the symfony type instead of yours. You can see the symfony TimeType has an option called widget so the formtype is expecting this type.
So try to rename your TimeType to something else like TicketTimeType.
Or you can rename your block prefix like this in your TimeType:
public function getBlockPrefix()
{
return "ticket_time_type";
}
Is it possible to call a sidebar in node.html.twig in Drupal 8?
Something like that :
<article{{ attributes }}>
{{ title_prefix }}
{% if not page %}
<h2{{ title_attributes }}>
{{ label }}
</h2>
{% endif %}
{{ title_suffix }}
{% if display_submitted %}
<footer>
{{ author_picture }}
<div{{ author_attributes }}>
{% trans %}Submitted by {{ author_name }} on {{ date }}{% endtrans %}
{{ metadata }}
</div>
</footer>
{% endif %}
<div{{ content_attributes }}>
{{ content }}
</div>
<div{{ content_attributes }}>
{{ sidebar}}
</div>
I would like to display a different sidebar for each node.
You can try this solution found here http://atendesigngroup.com/blog/making-region-content-available-node-templates-drupal-8:
/**
* Implements hook_preprocess_node() for NODE document templates.
*/
function THEME_preprocess_node(&$variables) {
// Allowed view modes
$view_mode = $variables['view_mode']; // Retrieve view mode
$allowed_view_modes = ['full']; // Array of allowed view modes (for performance so as to not execute on unneeded nodes)
// If view mode is in allowed view modes list, pass to THEME_add_regions_to_node()
if(in_array($view_mode, $allowed_view_modes)) {
// Allowed regions (for performance so as to not execute for unneeded region)
$allowed_regions = ['primary_content'];
THEME_add_regions_to_node($allowed_regions, $variables);
}
}
/**
* THEME_add_regions_to_node
*/
function THEME_add_regions_to_node($allowed_regions, &$variables) {
// Retrieve active theme
$theme = \Drupal::theme()->getActiveTheme()->getName();
// Retrieve theme regions
$available_regions = system_region_list($theme, 'REGIONS_ALL');
// Validate allowed regions with available regions
$regions = array_intersect(array_keys($available_regions), $allowed_regions);
// For each region
foreach ($regions as $key => $region) {
// Load region blocks
$blocks = entity_load_multiple_by_properties('block', array('theme' => $theme, 'region' => $region));
// Sort ‘em
uasort($blocks, 'Drupal\block\Entity\Block::sort');
// Capture viewable blocks and their settings to $build
$build = array();
foreach ($blocks as $key => $block) {
if ($block->access('view')) {
$build[$key] = entity_view($block, 'block');
}
}
// Add build to region
$variables[$region] = $build;
}
}
I used this hook to override node. You can pass {{ primary_content }} in your node.html.twig
I have a counting problem in phalcon volt. I have a table named category and there I have two columns id and cname, and also have a table blog and there is a column category. I want to show how many post have in each category.
When I insert a post into blog table, in category column I'm inserting its category id. First of I just retrieve list of all category like this:
[controller]
$categories = Category::find();
$this->view->setVar('category', $categories);
$cx = Blogs::find();
$this->view->setVar('cates',$cx);
[Volt]
{% for categories in category %}
<a href="blog/category/{{categories.cname}}" class="tags">{{ categories.cname }}
<span>[
{% for cx in cates %}
{%if cx.category === categories.id %}
<?php echo(count($cx->category)); ?>
{% endif %}
{% endfor %}
]</span></a>
{% endfor %}
Its render like "1 1 1" or "1 1" or "1" but it should render like "3" or "2" or "1" whats my wrong?
I also tried like this but did not get the expected output:
{% for categories in category %}
<a href="blog/category/{{categories.cname}}" class="tags">{{ categories.cname }}
<span>[
{% for cx in cates %}
{%if cx.category === categories.id %}
{% if loop.first %} {{ loop.length }} {% endif %}
{% endif %}
{% endfor %}
]</span></a>
{% endfor %}
Have you defined your relationships between your models in Phalcon?
If so, you can use the built in commands to query the total amount of posts for each category
Example from the documentation:
You can also use “count” prefix to return an integer denoting the count of the related records:
$robot = Robots::findFirst(2);
echo "The robot has ", $robot->countRobotsParts(), " parts\n";
I don't have much experience with Volt templating, but I guess it will be something like:
{% for categories in category %}
<a href="blog/category/{{categories.cname}}" class="tags">{{ categories.cname }}
<span>[
{{ categories.countBlogs }}
]</span></a>
{% endfor %}
Refer to: https://docs.phalconphp.com/en/latest/reference/models.html#taking-advantage-of-relationships
UPDATE - model relations
[model: Category]
public function initialize()
{
// id => primary key name of the Category table
// Blogs => name of the table you want to create a relationship with
// category => name of the foreign key column in your relationship table
$this->hasMany('id', 'Blogs', 'category');
}
[model: Blogs]
public function initialize()
{
// category => blog column name which refers to the ID in the Category table
// Category => name of the Category table
// id => name of the primary key column in the Category table
$this->belongsTo('category', 'Category', 'id');
}
No Sir, its not working. But i just solved my problem like this :
[controller]
$categories = Category::find();
$this->view->setVar('category', $categories);
[volt]
{% for categories in category %}
<a href="blog/category/{{categories.cname}}" class="tags">{{ categories.cname }}
<span>[
<?php
$catcount = $this->modelsManager->executeQuery("SELECT Blogs.category FROM Blogs WHERE Blogs.category = $categories->id");echo(count($catcount));
?>
]</span></a>
{% endfor %}
Now its working as expected. and here i dont make any relations ion model.Is it ok Sir. Please! Thnx