Drop down/Sub-menus in KeystoneJS - keystonejs

I'm currently in the process of developing a website. As part of the requirements, I need to include dropdown menu/sub menu from some of the main menu items. I'm able to create main menu items with KeystoneJS but I can't seem to find a tutorial on how to implement sub-menu items. How should I go about it?

Your question is a little unclear, but I'm assuming you're talking about updating the navigation bar that you get given after running the generator, and not about the admin UI itself?
If so, it will depend on what templating engine you use. I've done this myself with the handlebars template engine. I just added a locals.subsection, similar to locals.section.
I then updated routes/middleware to look like this:
locals.navLinks = [
{ label: 'Home', key: 'home', href: '/' },
{ label: 'About Us', key: 'about', pages: [
{ label: 'What We Do', subkey: 'whatwedo', href: "/whatwedo" },
{ label: 'Our Journey', subkey: 'journey', href: "/journey" }
] },
{ label: 'Blog', key: 'blog', href: '/blog' }
];
where in the above example, the "About Us" menu item will be a drop down, and the other two will not be. Then on the routes for your individual pages, you'll need to specify the section, and also the subsection if you want it to be a dropdown. In the above example, the whatwedo route has locals.section: about and locals.subsection: whatwedo.
You'll then need to update your default layout. For me, it's written in handlebars, and so looked like this:
{{# each navLinks}}
{{#if href}}
<li {{#ifeq ../../section key}}class="active"{{/ifeq}}>
{{ label }}
</li>
{{else}}
<li class="dropdown{{#ifeq ../../section key}} active{{/ifeq}}">
{{ label }} <span class="caret"></span>
<ul class="dropdown-menu">
{{#each pages}}
<li {{#ifeq ../../../subsection subkey}}class="active"{{/ifeq}}>
{{ label }}
</li>
{{/each}}
</ul>
</li>
{{/if}}
{{/each}}
I realise you are probably using jade rather than handlebars, but hopefully you'll be able to 'translate' this code.
Apologies if I've misinterpreted your question. Hope this helps.

Related

Nuxt Menu links from API...How can i detect if its a Nuxt link :to or :href?

Im building my main menu from an API :
<b-navbar-nav>
<div v-for="result in resultsmenu" :key="result.id">
<span class="hoverlink">
<nuxt-link :to="result.slug">{{result.title}}</nuxt-link>
</span>
</div>
</b-navbar-nav>
Everythings works well but one problem is in the menu from the API ..One link is external with an "href" like : https://ww.instagram.com so nuxt-link process it like a internal route i end up with :
http://localhost:3000/https://ww.instagram.com
I was wondering if there is a way to tell Nuxt that if a link is an "href" type: "link" to handle it like an external link instead of an nuxt-link to: ?
Thank you
One way to achieve this would be to use a computed property.
Assuming your resultsmenu data looks something like...
resultsmenu: [
{slug: 'http://www.website.com', title: 'link to website.com'},
{slug: '/test', title: 'link to a website.com'},
{slug: '/yay', title: 'link to b website.com'},
{slug: 'http://www.website.com', title: 'link to c website.com'}
]
You can do...
computed: {
menuLinks() {
let links = []
this.resultsmenu.forEach(link => {
let menuItem = {}
menuItem.isHttp = !!link.slug.includes('http');
menuItem.target = link.slug
menuItem.title = link.title
links.push(menuItem)
})
return links
}
}
Then in your template:
<div v-for="(result, index) in menuLinks" :key="index">
<span>
<nuxt-link v-if="!result.isHttp" :to="result.target">{{result.title}}</nuxt-link>
<a v-else :href="result.target">{{result.title}}</a>
</span>
</div>

Using Slots or slot-scopes in v-for loops to access properties?

I'm having a difficult time understanding slots for some reason and why they should even be used. The only reason I can think of that would be nice for usuage is if we can reference specific properties within a v-for loop of an element and output different templates quicker perhaps...
So, am thinking, and possibly I could be wrong in thinking this, but if I have a variable like so:
<script>
const items: [
{
label: 'My Label',
url: '#',
headerTitle: 'My Header Title'
},
{
label: 'My Label 2',
url: 'https://www.myurl.com',
headerTitle: 'My Header Title 2'
},
{
label: 'My Label 3',
url: 'https://www.myurl3.com'
}
]
export default {
data () {
return {
items: items
}
}
}
</script>
And than in the template, possibly this:
<template>
<div v-for="(item, index) in items" :key="item.id">
<template slot-scope="headerTitle">
<h1>{{ item.headerTitle }}</h1>
</template>
<template slot-scope="label">
<div class="mylabel">
{{ item.label }}
</div>
</template>
<template slot-scope="url">
<a :href="item.url">{{ item.label }}</a>
</template>
</div>
</template>
I don't know if this makes sense or not, but basically using the property as a slot-scope and than for everytime that property is defined, it will output something. But this doesn't work properly. Is this not what slot-scopes are for within component v-for loops? Is this not how to use these properties of an array of objects?
This kinda makes sense to me. Anyways to do it like this perhaps?

How to dynamically add attributes to elements in vue.js?

Given an items array of objects:
items: [{
label: 'My Link',
attrs: {
href: '/route',
target: '_blank',
title: 'Some title',
},
},{
label: 'My Link 2',
attrs: {
href: '/route2',
target: '_self',
title: 'Some title 2',
},
}];
My vue has a v-for that loops through a list of items:
<ul>
<li v-for="item in items">
<a ADD_ITEM_ATTRIBUTES_HERE>{{ item.label }}</a>
</li>
</ul>
How can I loop through each item's attribute and dynamically add it to the anchor element where the Attribute name is the object key and the attribute value is its matching value?
I'm coming from jQuery world where this kind of manipulation is pretty straight forward, but I'm not sure how to modify the DOM in this case.
Most questions I find here have to do with checking if an element has a prop or meets a condition to set its value. I'm not trying to do that. In my case I don't know what the prop will be nor its value.
Since you already have attributes in an object, you can directly pass it to v-bind; Also see bind an object of attributes example:
<a v-bind="item.attrs">{{ item.label }}</a>
This will result in keys in attrs object as attributes and values in attrs as corresponding values.

Event driven binding / rebinding of v-model / v-bind?

I'm really struggling on how to implement a pattern inline with the "Vue philosophy".
Imagine a list of items that you'd like to edit. There are numerous examples of how to edit those items "inline". But I'd like to edit my items through the same, persistent form. So when you click a list item, the form input "rebinds" to clicked list item.
Here's a working example: http://jsbin.com/sopakid/3/edit?html,js,output which uses a method (updateRecord) to copy the form input (bound to editRecord), to the referenced li's data binding (messages[index]).
data: {
messages: [
{ name: "Dale Cooper", message: "Black as midnight on a moonless night" },
{ name: "Shelly Johnson", message: "I've got one man too many in my life and I'm married to him." },
{ name: "Sheriff Truman", message: "Jelly donuts?"}
],
editRecord:
{ name: "", message: "" }
},
updateRecord: function(){
var index = this.editRecord.index;
this.messages[index].name = this.editRecord.name;
this.messages[index].message = this.editRecord.message;
}
Looking for any insight as to how to better implement this pattern. Thanks!
Idiomatically, you don't really need any methods in this case. You can set the editRecord directly in the template. Additionally, if you set the editRecord to the selected message, then you don't even need an update button or a need to keep track of the index.
var app = new Vue({
el: '#app',
data: {
editRecord:{ name: null, message: null },
messages: [
{ name: "Dale Cooper", message: "Black as midnight on a moonless night" },
{ name: "Shelly Johnson", message: "I've got one man too many in my life and I'm married to him." },
{ name: "Sheriff Truman", message: "Jelly donuts?"}
]
}
});
These are the changes I made to your template
<div id="app">
<div class="messages">
<ul>
<li class="message" v-for="(message, index) in messages" #click="editRecord = message">
<div class="message__name">
{{message.name}}
</div>
<div class="message__body">
{{message.message}}
</div>
</li>
</ul>
</div>
<div class="edit-form" v-if="editRecord">
<label for="name">Name</label>
<input name="name" type="text" placeholder="Name" v-model="editRecord.name">
<label for="message">Message</label>
<textarea name="message" id="" cols="30" rows="6" v-model="editRecord.message"></textarea>
</div>
</div>
Here is your fiddle updated.
The result takes advantage of Vue's reactivity and as you edit in your form you can see the changes taking place in the list as well.
Some people may like the approach you've taken though, where the edits they make are not complete until they specify they are. A lot of this is a matter of taste.
I would warn against using index to track your selected record, however. If the list changes underneath you, the indexes change. Use an id property on your messages. If you go with the reactive approach though, you don't really need that.

How to use icon in routes using Durandal?

I was looking around the documentation of the structures of these route-info object, but I didn't find any. Since Durandal use other JS libs, I don't sure what is this belong to (maybe sammy?).
I am facing 2 problems:
Problem #1 I want to use an icon in the route information, and I found that I could use title or caption to accomplish that...
Ugly Option 1: using icon info in the caption
{ route: 'dashboard', title: 'Dashboard', moduleId: 'viewmodels/dashboard', nav: true, caption: 'icon-dashboard' },
and do some binding like this:
<i data-bind="attr: { 'class': caption}"></i>
<a data-bind="attr: { href: hash }, html: title"></a>
or Ugly Option2: using icon html code in the model
{ route: 'dashboard', title: 'Dashboard', moduleId: 'viewmodels/dashboard', nav: true, caption: '<i class="icon-plus-sign"></i> Dashboard' }
and the binding will be:
<a data-bind="attr: { href: hash }, html: caption"></a>
I personally like option 1, because the is separation of data and display. But the property (caption) is not the best place to put it... what other options are??? I saw people using setting, but again, what settings-options are?? can I create my own icon property?
Other Problem How to design sub-menu... if is there a property to reference a parent-route??
Update 8/23/2013 I found this info about Child Routers
You can add your own properties to the route object. This is the good thing about JavaScript!
So as you say, you could add a settings object to the route like this:
{ route: 'dashboard', title: 'Dashboard', moduleId: 'viewmodels/dashboard', nav: true, settings : { caption: 'icon-dashboard', another :'property'} }
And just do the binding the same way you were doing:
<i data-bind="attr: { 'class': settings.caption}"></i>
<a data-bind="attr: { href: hash }, text: title"></a>
Just make sure that all your objects that will be bound in the UI contain the settings.captionor add extra logic in the binding to manage route objects that which property isundefined.