Jump to content

Dropdown Menu


luzox

Recommended Posts

I see your problem, this array string below...

'list_tpl' => '<li class="dropdown">||</li>'

Overrides has_children class as default.  And this string will add 'dropdown' class to whole element that has <li>.  Use this string...

'has_children_class' => 'has_children',

If you only want to change <li> classname that have children only.  BTW, you don't really need to input entire stack of arrays since the list are already default,  only randomly pick one that need to override it's defaults. 

Hope that helps

  • Like 1
Link to comment
Share on other sites

@MaryMatlow, the commented default options in the MarkupSimpleNavigation docs say this...

'list_tpl' => '<li%s>||</li>',
// template string for the items. || will contain entries, %s will replaced with class="..." string

%s is a placeholder for the dynamic classes such as 'has_children', 'level-n', etc. If you remove the %s placeholder in list_tpl as you have done in your options there is nowhere for the dynamic classes to be inserted.

So revert back to the default for list_tpl (and as @Speed said, you only need to set options you are changing from the default). If you want 'dropdown' to be added to the classes of every list item you set this...

'list_field_class' => 'dropdown',

...or if you want it to be added to the classes of only list items that have children you set this...

'has_children_class' => 'has_children dropdown',

 

  • Like 2
Link to comment
Share on other sites

@MaryMatlow I believe this is an active community here...

Let make it lot clear for you. Here what you did...

 <?php
                    $nav = $modules->get("MarkupSimpleNavigation"); 
                    $nav_options = array(
                    'list_tpl' => '<li class="dropdown">||</li>'
                    );
                    echo $nav->render($nav_options);
                ?> 

The result...

<nav>
  <ul>
    <li class="dropdown">...</li>
    <li class="dropdown">...</li>
    <li class="dropdown">...</li> /*has children*/
         <ul>
    		<li class="dropdown">...</li>
    		<li class="dropdown">...</li>
    		<li class="dropdown">...</li>
    		<li class="dropdown">...</li>
  		</ul>
    <li class="dropdown">...</li>
  </ul>
</nav>

Entire <li> is getting class called dropdown, even it will override <li> default class. Now if you change this...

 <?php
                    $nav = $modules->get("MarkupSimpleNavigation"); 
                    $nav_options = array(
                    'has_children_class' => 'has_children dropdown',
                    );
                    echo $nav->render($nav_options);
                ?> 

The result will show <li> with children contain two classes "has_children" and "dropdown" just like @Robin S showed you. 

<nav>
  <ul>
    <li>...</li>
    <li>...</li>
    <li class="has_children dropdown">...</li> /*has children*/
         <ul>
    		<li>...</li>
    		<li>...</li>
    		<li>...</li>
    		<li>...</li>
  		</ul>
    <li>...</li>
  </ul>
</nav>

You can as well use only one class name "dropdown" this..

 <?php
                    $nav = $modules->get("MarkupSimpleNavigation"); 
                    $nav_options = array(
                    'has_children_class' => 'dropdown',
                    );
                    echo $nav->render($nav_options);
                ?> 

and it will assign <li>  with only class name "dropdown"  as result...

<nav>
  <ul>
    <li>...</li>
    <li>...</li>
    <li class="dropdown">...</li> /*has children*/
         <ul>
    		<li>...</li>
    		<li>...</li>
    		<li>...</li>
    		<li>...</li>
  		</ul>
    <li>...</li>
  </ul>

or leave blank....

 <?php $nav = $modules->get("MarkupSimpleNavigation"); ?> 

the result still will show <li> with children with default class "has_children"  since MSN detects existing children

  <ul>
    <li>...</li>
    <li>...</li>
    <li class="has_children">...</li> /*has children*/
         <ul>
    		<li>...</li>
    		<li>...</li>
    		<li>...</li>
    		<li>...</li>
  		</ul>
    <li>...</li>
  </ul>

Hope this one really helps.

  • Like 3
Link to comment
Share on other sites

Thanks for your responses. I have applied your suggestions and this is what my code looks like now. The issue that I see with the code is that, every single <a href> has the attributes class="dropdown-toggle" and data-toggle="dropdown". When only the links where the "has_children" class gets applied should have those. Since these attributes are applied everywhere the links become unclickable.

Here's the output markup:

<nav class="collapse navbar-collapse navbar-right" role="navigation">
                    <div class="main-menu"><ul class="nav navbar-nav">
	<li class="level-1 has_children dropdown"><a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="/classes/">Classes</a>
		<div class="dropdown-menu"><ul>
			<li class="level-2"><a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="/classes/class-schedule/">Class Schedule</a></li>
			<li class="level-2"><a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="/classes/class-descriptions/">Class Descriptions</a></li>
			<li class="level-2"><a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="/classes/new-to-yoga/">New to Yoga</a></li>
			<li class="level-2"><a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="/classes/teachers/">YogaSpace Teachers</a></li>
		</ul></div>
		</li>
	<li class="level-1"><a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="/workshops/">Workshops</a></li>
	<li class="level-1"><a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="/prices/">Prices</a></li>
	<li class="level-1 has_children dropdown"><a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="/about/">About Us</a>
		<div class="dropdown-menu"><ul>
			<li class="level-2"><a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="/about/what-we-offer/">What We Offer</a></li>
			<li class="level-2"><a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="/about/the-studio/">The Studio</a></li>
			<li class="level-2"><a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="/about/gallery/">Gallery</a></li>
			<li class="level-2"><a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="/about/community/">Community</a></li>
			<li class="level-2"><a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="/about/join-our-team/">Join Our Team</a></li>
		</ul></div>
      </li>
	<li class="level-1"><a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="/contact/">Contact</a></li>
</ul></div></nav>

 

Here is my code:

<?php
  $treeMenu = $modules->get("MarkupSimpleNavigation"); // load the module
  $options = array(
    
    'has_children_class' => 'has_children dropdown',
    // overwrite class name for entries with children

    'levels' => true,
    // wether to output "level-1, level-2, ..." as css class in links


    'max_levels' => 2,
    // set the max level rendered

   
    'selector' => 'template!=MediaLibrary',
    // define custom PW selector, you may sanitize values from user input

   
    'outer_tpl' => '<nav class="collapse navbar-collapse navbar-right" role="navigation">
                    <div class="main-menu"><ul class="nav navbar-nav">||</ul></div></nav>',
    // template string for the outer most wrapper. || will contain entries

    'inner_tpl' => '<div class="dropdown-menu"><ul>||</ul></div>',
    // template string for inner wrappers. || will contain entries

    'list_tpl' => '<li%s>||</li>',
    // template string for the items. || will contain entries, %s will replaced with class="..." string

    'list_field_class' => '', // string (default '') add custom classes to each list_tpl using tags like {field} i.e. {template} p_{id}

    'item_tpl' => '<a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="{url}">{title}</a>',
    // template string for the inner items. Use {anyfield} and {url}, i.e. {headline|title}, if field is of type image it will return url to image (first image if multiple)

    'item_current_tpl' => '<a class="current" href="{url}">{title}</a>',
    // template string for the active inner items.

  
);

  echo $treeMenu->render($options); // render menu
 ?>

 

 

 

 

Link to comment
Share on other sites

Since you use

    'item_tpl' => '<a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="{url}">{title}</a>',

these classes of course will be added to all the <a> elements, independent of the <li> having has_children or not.

The point is that the class has_children is an optional class for the <li>, not for the <a>. So a workaround could be changing the CSS.

Assuming your class dropdown-toggle is defined like this:

a.dropdown-toggle {
    /* your styles here */
}

Then change this to

li.has_children > a {
    /* your styles here */
}

So your styles are applied just to those <a> elements which are direct children of a <li> element having the has_children_class.

(Didn't try it, just written here...)

 

A quite different (and way more complicated) approach would be the use of the "hook for custom item string (new in 1.2.0)" -

see the README of http://modules.processwire.com/modules/markup-simple-navigation/

Edited by ottogal
Link to comment
Share on other sites

@ottogal Thanks for your reply, but I don't think this can be solved by css rules.

Is there a standard way to apply this navigation code? What I'm trying to do here is nothing special. All I want is first level nav, and the second level dropdown menu for the items with children. The problem is with "data-toggle=dropdown" attribute. When I remove it everything works fine, except in responsive mobile mode, the items with dropdown menu don't open up. And when I don't remove it, none of the menu items at any level are clickable.

    'item_tpl' => '<a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="{url}">{title}</a>',

Again, this is all pretty standard, and it works for the rest of you. So I don't why it shouldn't it my case. It's so frustrating.

Thanks.

Link to comment
Share on other sites

@MaryMatlow  I believe you have used bootstrap navigation structure, correct me if I am wrong? So you said, it worked when you remove data-toggle attributes. Your issues  could be more likely to conflict between data-attribute and JS/JQuery since you assigned multiple data-toggle attributes. I could be wrong, only way to know is open web-dev console tab and see if you have encountered error. 

Here other thing... Can I suggest your code structure to look like this...

<nav class="collapse navbar-collapse navbar-right" role="navigation">
    <div class="main-menu">
        
        <?php
          $treeMenu = $modules->get("MarkupSimpleNavigation"); // load the module
            $options = array(

                'has_children_class' => 'dropdown',
                'max_levels' => 2
                selector' => 'template!=MediaLibrary',
                'outer_tpl' => '<ul class="nav navbar-nav">||</ul>',
                'inner_tpl' => '<div class="dropdown-menu"><ul>||</ul></div>',
                'item_tpl' => '<a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" aria-controls="navbar" href="{url}">{title}</a>',
                'item_current_tpl' => '<a class="current" href="{url}">{title}</a>',
            );

                echo $treeMenu->render($options); // render menu
        ?>
    </div><!--end of .main-menu-->
</nav>

I haven't tested it yet, but you don't really need to have <nav>. <div> inside MSN, since MSN is specifically for <ul><li> and <a>.. 

Link to comment
Share on other sites

@Speed Thank you and others for your patient explanations. I tried your code with no success. The same problem persists. When I look into Dev console I get this error. You were right, it has to do with js:

main.js:50 Uncaught TypeError: jQuery(...).scrollingTo is not a 
function(…)(anonymous function) 
@ main.js:50(anonymous function) 
@ main.js:51i 
@ jquery.min.js:2fireWith 
@ jquery.min.js:2ready 
@ jquery.min.js:2J 
@ jquery.min.js:2

When I click on main.js it points to this function:

jQuery(document).ready(function(){
	"use strict";
	new WOW().init();


(function(){
 jQuery('.smooth-scroll').scrollingTo();
}());

});

It seems it has something to do with smooth scrolling function. This is strange. How can this be resolved?

Thanks once again. :-)

Link to comment
Share on other sites

main.js:50 Uncaught TypeError: jQuery(...).scrollingTo is not a function(…)(anonymous function)

This mean .scrollingTo is not a JQuery API function or never recognized as official function. If there is/are another Javascript fie that creates .scrollingTo as function, make sure script source url is included at bottom of HTML before end of <\body> or the url of script doesn't have typo error... I have strong feeling it should be  .scrollTo instead. have a look here 

Link to comment
Share on other sites

7 hours ago, MaryMatlow said:

What I'm trying to do here is nothing special. All I want is first level nav, and the second level dropdown menu for the items with children.

Well, the markup you want to output is actually quite complicated. Needlessly complicated too IMHO, but that's Bootstrap's fault. @Soma, author of MarkupSimpleNavigation, said it pretty well:

On 11/03/2014 at 6:20 AM, Soma said:

I don't know Bootstrap well and what extraordinary unnecessary complicated data's and id's and classes it needs. Also I don't want to add features just for Bootstrap.

On 20/08/2013 at 2:28 AM, Soma said:

I'm lucky I don't use Bootstrap because it's annoying :D

Couldn't agree more. Soma does have a Gist for generating Bootstrap markup with MSN, but it's for Bootstrap 2: https://gist.github.com/somatonic/6258081

 

Here is one way you could generate markup for your menu:

$nav = $modules->get('MarkupSimpleNavigation');

$options = array(
    'has_children_class' => 'has_children dropdown',
    'levels' => true,
    'max_levels' => 2,
    'selector' => 'template!=MediaLibrary',
    'outer_tpl' => '<nav class="collapse navbar-collapse navbar-right" role="navigation"><div class="main-menu"><ul class="nav navbar-nav">||</ul></div></nav>',
    'inner_tpl' => '<div class="dropdown-menu"><ul>||</ul></div>',
    'item_current_tpl' => '<a class="current" href="{url}">{title}</a>',
);

$nav->addHookAfter('getItemString', function(HookEvent $event) use($options) {
    $item = $event->arguments('page');
    if($item->hasChildren() && count($item->parents) < $options['max_levels']) {
        $class = $item == $this->page ? ' current' : '';
        $event->return = "<a class='dropdown-toggle{$class}' data-toggle='dropdown' aria-expanded='false' aria-controls='navbar' href='{$item->url}'>{$item->title}</a>";
    }
});

echo $nav->render($options);

Don't know about your JS issue, but that won't be PW-related.

  • Like 1
Link to comment
Share on other sites

@Robin S Thank you! Thank you! Your code worked, like a charm. Really indebted to you and the others who replied to my persistent queries. Really appreciate it.

I don't see how this is a Bootstrap-sepecific problem. Am I the only one using Bootstrap with Processwire, and facing this problem?

Just for my information, i would like to know what Framework gels best with Processwire? I concede that Bootstrap can be a bit bloated, is there a leaner and meaner framework out there?

Thanks

  • Like 1
Link to comment
Share on other sites

1 hour ago, MaryMatlow said:

I don't see how this is a Bootstrap-sepecific problem.

It's Bootstrap-specific in that Bootstrap requires you to add (among many, many other things) an unnecessary data-toggle="dropdown" attribute to the <a> element. It's unnecessary as that element can already be targeted as a direct child of an <li> element with "has_children" class (or whatever other class you might want to use for dropdown menu purposes). That is what @ottogal referred to above:

18 hours ago, ottogal said:

Then change this to


li.has_children > a {
    /* your styles here */
}

So your styles are applied just to those <a> elements which are direct children of a <li> element having the has_children_class.

 

1 hour ago, MaryMatlow said:

Am I the only one using Bootstrap with Processwire, and facing this problem?

MarkupSimpleNavigation does not equal ProcessWire - it's a third-party module for ProcessWire. PW allows you to generate your markup any way you choose. Personally I find MSN to be a very useful module but it's not compulsory to use it. Some people create their own menu markup from scratch using just the API and basic PHP functions like foreach(). And there are other modules for generating menu markup such as Menu Builder (haven't used it myself).

 

1 hour ago, MaryMatlow said:

what Framework gels best with Processwire

I'm not a good one to answer this as I don't like CSS frameworks - I find them a hindrance rather than a help. I prefer to create my stylesheets for each project from scratch using SCSS. That way there's no bloat and I can build exactly to my design mockups without needing to conform to any framework expectations. I understand UIKit is popular with others though.

  • Like 4
Link to comment
Share on other sites

7 hours ago, MaryMatlow said:

is there a leaner and meaner framework out there?

I recommend: http://materializecss.com/ I'm the type who likes css "frameworks”. It is because I do not spend hours working with css, neither do I have the time to fight browser incompatibilities. Those with a decent knowledge of css and supporting technologies (like preprocessors, task runners, etc..) generally do not like Bootstrap like frameworks, especially if they do not work in teams. They tend to like low level “frameworks” (or just simple css grid packages) that give them more freedom, or they do not use any of these at all, or perhaps just their own.

However, I think it can be quite useful to learn one of these, because if you are not developing frontends on a daily bases, then they can speed up a lot. Sure, there are situations when one finds the chosen framework to be an obstacle when dealing with a particular problem, but still, they can be really useful.

I spent a considerable amount of time to find an easy to use versus versatile and feature rich framework and I think Materialize CSS is the way to go for "experienced beginners" like me. If you are also in this “category”, then I highly recommend it. One can even easily customize it by vanilla css overwrites if you do not want to go the preprocessor way (just yet).

Out of the box solutions like Bootstrap, UIKit and others are most useful for teams working on the same project, as these packages define the standard to which everyone can adhere to, so that is why UIKit for the ProcessWire admin would be a good choice, for example. However, solo freelancers working alone have more freedom regarding the path they choose to take...

Edited by szabesz
...the ProcessWire admin...
  • Like 3
Link to comment
Share on other sites

13 hours ago, MaryMatlow said:

Just for my information, i would like to know what Framework gels best with Processwire? I concede that Bootstrap can be a bit bloated, is there a leaner and meaner framework out there?

Glad to know your issues have been solved, Blending Bootstrap with CMS can become cumbersome and time consuming. At least you probably have learned something about PW. Here's list UI framework, "a lighter version of bootstrap". 

- Kube

- Pure

- Skeleton

- Concise

and many more...You can even build your own framework yourself. 

  • Like 3
Link to comment
Share on other sites

Thank you for your thoughtful replies. I will surely explore the suggestions you've made. I've found that working with a framework is a good thing, it frees you from sweating over small/routine stuff. But that's me. In any case, I'm loving Processwire although it has been/and is going to be a steep learning curve. I'm a PHP novice. Yet, I can see the freedom and flexibility it affords. Thanks again.

  • Like 4
Link to comment
Share on other sites

3 minutes ago, MaryMatlow said:

@Robin S The code worked fine on localhost, but when I migrate the site on server it throws this error:

Fatal error: Using $this when not in object context

Would you know how to fix this?

Thanks.

 

Likely a PHP version difference. Try replacing:

$this->page

with:

wire('page')

 

  • Like 3
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...