Dust.js context issue? - templates

I have the following partial:
<ul class="navbar">
{#nav_links}
<li class="navbar__link {?sub_menu}more{/sub_menu}">
{label}
{?sub_menu}
<ul class="navbar__link--sub">
{#sub_menu}
<li class="navbar__link--sub {?sub_menu}more{/sub_menu}">
{label}
</li>
{/sub_menu}
</ul>
{/sub_menu}
</li>
{/nav_links}
</ul>
With JSON:
{
title: "page title",
nav_links: [
{
link: "home",
label:"Home"
},
{
link: "products",
label:"Products",
sub_menu: [
{link: "link1", label: "Product A"},
{link: "link2", label: "Product B"},
{link: "link3", label: "Products C", sub_menu: [
{link: "link3-1", label: "Sub Product A"},
{link: "link3-2", label: "Sub Product B"}
]},
]
}
]
}
The issue I've run into is the nested sub_menu property, all sub menu items add the more class regardless if they have a nested sub_menu or not. I thought the context would have shifted like it does with link and label, however it seems to still refer to the initial sub_menu like the first conditional and section tags do. I've renamed the nested sub_menu property in the JSON and partial tag, context works correctly then. Is there a way to still use the sub_menu property name? Or reference the child property such as sub_menu.sub_menu?

By default, Dust will walk up the context if it doesn't find a key at a certain level. However, you're wanting to explicitly check only the current level of the context. To do this in Dust, prefix the key with a dot:
<li class="navbar__link--sub {?.sub_menu}more{/sub_menu}">

Related

How to retrieve layout of an item using JSS

I am really new to JSS and I am very confused by the docs and how Sitecore is supposed to assemble layout information. I am trying to retrieve layout information of an item using JSS for one of our MVC project. The item in question renders fine in the browser using our traditionnal MVC stack. However I am unable to retrieve layout information of that item using JSS.
The item in question is based on the standard template and has the following presentation/layout details:
The layout points to a cshtml file.
The cshtml file contains the HTML layout, and a placeholder rendered using #Html.Sitecore().Placeholder("Menu")
The content of the placeholder is defined in Sitecore Layout Details dialog using a control/rendering named "Menu".
The rendering "Menu" points to a controller named Web.Controllers.MenuController and action named GetMenu
Content of the cshtml file:
#using Sitecore.Mvc
<main id="main" class="content group advise-area" role="main">
<div class="inner inner-carousel advise-area-content">
<div class="row">
<div class="col-2-2">
#Html.Sitecore().Placeholder("Menu")
</div>
<div class="col-2-2">
#Html.Raw(Model.Content)
</div>
</div>
</div>
</main>
When retrieving the layout information of the item using the render endpoint (/sitecore/api/layout/render/jss?item={item_id}&...). I get the fields values of the item, but I do not get any presentation details nor placeholder information.
{
"sitecore": {
"context": {
"pageEditing": false,
"site": {
"name": null
},
"pageState": "normal",
"language": "fr",
"itemPath": "/my-item"
},
"route": {
"name": "prendre-route-securite",
"displayName": "prendre-la-route-en-toute-securite",
"fields": {"Content": {"value": "My Content"}},
"databaseName": "web",
"deviceId": "fe5d7fdf-89c0-4d99-9aa3-b5fbd009c9f3",
"itemId": "85cac673-2cfb-496c-ba62-0f1d634ae241",
"itemLanguage": "fr",
"itemVersion": 1,
"layoutId": "b39337a1-8bb5-44c3-ba97-0dce8ef517f6",
"templateId": "34c34e2b-f2ac-405f-afb3-d0185bc936bb",
"templateName": "ArticleZoneConseils",
"placeholders": {}
}
}
}
The documentation says I am supposed to put some values inside the Layout Service Placeholders field of the layout. But I have no clue of what I should put in there to get the placeholder data showing in the REST query.

Vuejs, removing element from nested lists

This is a followup question on VUEJS remove Element From Lists?, where they give various methods (this.$remove, splice, this.$delete) for dynamically removing a element from a list. I was trying to understand how to apply this to a nested loop; here's mine in three+ levels, somewhat stripped-down:
<template v-for="(labtype,index) in labIRlist">
<template v-for="(lab,index2) in labtype">
<tr v-for="(IR,index3) in lab.irs" :key="IR.irn">
<td><p>{{ lab.hidtxt }}_{{ lab.mnem }}</p></td>
<td><p>{{ lab.PNL }}</p></td>
<td><p>{{ IR.provider}} {{ IR.psurv }}</p></td>
<td><p>{{ IR.year }}-{{ IR.eventno }}</p></td>
<td><p>{{ IR.analytes }}</p></td>
<td><p>
<button type="button"
#click="deleteIR(IR.irn,index,index2,index3)">
DELETE
</button>
</p></td>
</tr>
</template>
</template>
Then there's Javascript for the deletion
methods: {
deleteIR: function(IRNum,index,index2,index3) {
// okay, delete!
//... code to do something at the database...
alert('IR successfully deleted!')
// don't show the deleted IR any more
this.labIRlist[index][index2].irs.splice(index3,1);
},
Awful, but I didn't know how to identify the correct element. And it still didn't work (AFAIK it does nothing, no change visible to the row). How should this be done - don't we know the right element from where deleteIR was called?
What is the better way to handle deleting an element within multiple
loops?
First of all, looking at how your template is built, we can assume that your data looks something like this:
labIRlist: [
[
{
hidtxt: "TEXT 1",
irs: [{ provider: "provider1" }, { provider: "provider11" }],
irn: "irn1",
},
{
hidtxt: "TEXT 2",
irs: [
{ provider: "provider2" },
{ provider: "provider22" },
{ provider: "provider222" },
],
irn: "irn2",
},
],
[
{
hidtxt: "TEXT 3",
irs: [{ provider: "provider3" }],
irn: "irn3",
},
],
],
If you want to delete one item from the nested irs array, all you need to do is to pass the irs array and the index of the item you want to delete, no need to do the whole path you are doing currently:
this.labIRlist[index][index2].irs.splice(index3,1);
So change your template to:
<button type="button" #click="deleteIR(lab.irs, index3)">
And the delete function is then simply:
deleteIR(IRS, index) {
IRS.splice(index, 1);
}
A DEMO for your reference
PS. Please always share a bit of your data when posting questions like this. Much easier to answer when not needing to create your own sample data like I did here.

Ember.js: binding to dynamic form inputs

I'm trying to figure out the proper way to collect "variable" personalized data on a product. The product has these personalized fields defined:
"personalization": [
{
"id": 234,
"maxlength": "128",
"prompt": "Text Line 1 (12 character limit)",
"required": "1"
},
{
"id": 235,
"maxlength": "128",
"prompt": "Text Line 2 (12 character limit)",
"required": "1"
}
],
Building a small form to collect that input would be fairly straightforward, except that personalized data can be different for each quantity. So if I order 2 of this item, it can have personalization:
FIRST ITEM
Text Line 1: Yarr
Text line 2: Matey
SECOND ITEM
Text Line 1: Swab
Text line 2: The poop deck
So basically the set of personalized fields needs to repeat for each quantity.
I've got the form built using a computed property:
personalizedForm: computed('quantity', function() {
let q = get(this, 'quantity');
let persform = [];
for (let i = 0; i < q; i++) {
persForm.push(get(this, 'model.personalization'));
}
return persForm;
}),
with this template:
{{#each personalizedForm as |quantity index|}}
Item {{add index 1}}
<ul>
{{#each quantity as |set|}}
<li class="label">{{set.prompt}}</li>
<li class="field">{{input value=????}}</li>
{{/each}}
</ul>
{{/each}}
And that shows a form like the image below. So that's great. But I just can't figure out exactly what to bind each form field to, and how. I imagine the "mut" and "get" helpers are the ticket, but I don't even know how to set up the object to save the data to.
Any help is appreciated!
I think I have this somewhat figured out. On the controller there's a property and a computed property that updates it if/when the quantity changes:
persModel: [], // will contain dynamic model
persModelUpdated: computed('quantity', function() {
let persModel = this.get('persModel');
let persPrompts = get(this, 'model.personalization');
// loop thru quantities
for (let i = 0; i < get(this, 'quantity'); i++) {
// if persModel does not have this set of prompts, push in a copy
if (!persModel.objectAt(i)) {
let copySet = Ember.copy(persPrompts, { 'deep': true });
persModel.pushObject(copySet);
}
}
return persModel;
})
In the template the fields are written out dynamically based on the computed property. I'm using the mut and get helpers to update a 'value' field within each set.
{{#each persModelUpdated as |thisQty index|}}
Item {{add index 1}}
<ul>
{{#each thisQty as |persSet|}}
<li>{{persSet.prompt}}</li>
<li>{{input value=(mut (get persSet 'value'))}}</li>
{{/each}}
</ul>
{{/each}}
I'm not sur to understand you want to find a way to get all the value from the dynamic form ?
You can try to serialize your form.
You have to put the balise form before and after your each like so
<form id="my_form">
{{#each personalizedForm as |quantity|}}
Item {{add index 1}}
<ul>
{{#each quantity as |set|}}
<li class="label">{{set.prompt}}</li>
<li class="field">{{input value=????}}</li>
{{/each}}
</ul>
{{/each}}
<form>
and then in your component .js you can get them by doing
const formArray = Ember.$('#my_form').serializeArray();
to get a array or
const form = Ember.$('#my_form').serialize(); to get a object

how to get kendoui grid popup add/edit form created from kendo template, show the correct title for add and edit operations?

I can't seem to find a simple way to set the title on a popup add and edit form launched from the kendoui grid, when it is created using a custom template. When I tried the following example, both Add and Edit operations had "Edit" in the title bar of the popup:
Markup:
<script id="popup-editor" type="text/x-kendo-template">
<p>
<label>Name:<input name="name" /></label>
</p>
<p>
<label>Age: <input data-role="numerictextbox" name="age" /></label>
</p>
</script>
<div id="grid"></div>
JavaScript:
$("#grid").kendoGrid({
columns: [
{ field: "name" },
{ field: "age" },
{ command: "edit" }
],
dataSource: {
data: [
{ id: 1, name: "Jane Doe", age: 30 },
{ id: 2, name: "John Doe", age: 33 }
],
schema: {
model: { id: "id" }
}
},
editable: {
mode: "popup",
template: kendo.template($("#popup-editor").html())
},
toolbar: [{ name: 'create', text: 'Add' }]
});
Fiddle demonstrating the issue: http://jsfiddle.net/codeowl/XN5rM/1/
The issue is that when you press the Add or Edit buttons, the title bar in the popup says: "Edit". I want it to say Add when you press the Add button and Edit when you press the Edit button.
Thank you for your time,
Regards,
Scott
If you want a simple solution, add code to the edit event of the grid to check to see if the model being created when edit is called is a new one or an existing one and set the text accordingly:
...
edit: function (e) {
//add a title
if (e.model.isNew()) {
$(".k-window-title").text("Add");
} else {
$(".k-window-title").text("Edit");
}
}
...
Hope this helps...
If the only thing that you need to do is add a title, you should use:
editable : {
mode : "popup",
window : {
title: "EdiciĆ³n",
}
},
You don't need to define a template unless you need to define something else.
Your modified Fiddle here : http://jsfiddle.net/OnaBai/XN5rM/2/

Nested loops: Access object from parent view

I've got basically two arrays of objects in one view:
App.List = Ember.View.extend({
students: [{ "name": "yehuda" }, { "name": "tom" }],
teacher: [{ "name": "mr. katz" }, { "name": "mr. dale" }]
});
My handlebars look something like this:
{{#each teacher}}
<li class="teacher">{{name}}</li>
{{#each students}}
// display students for this teacher
{{/each}}
}}
The obvious problem here is, that the students-array is not within the teacher-array but on the same "level". So how can I access the students-array?
Thanks!
It seems to be related to the view context, try to use {{view.students}}, I think it should work.
jsfiddle updated against comments: http://jsfiddle.net/Sly7/gdXfN/