Help Making This Layout into a Form

I’d like to make the page here into a GET method form in which the user can click on/click off multiple wearables and then click a “compare” submit button. The following page would pull data and display a table of specs. Can I do this with HTML/CSS, or do I also need Javascript? Specifically, my issues are:

  1. How do I turn each <li> item into a button?
  2. How do I make each <li> selectable and deselectable?
  3. How can I highlight each <li> when it is selected?

Thank you.

EDIT
page has since been revised, please see below

Yes, you need some kind of programming language for this. Moved to JS forum.

Not sure I understand the question.
Could you elaborate a little on what you are trying to do.

Sorry if I was unclear. I would like the user to be able to select multiple items and then click a submit button that would direct the user to a new URL containing the item IDs. Each item should highlight when selected and return to its normal state when not selected. I would prefer to be able to control the selected state style with css.

As with any problem, split it into small pieces and start with those.

Do that by adding a CSS class of selected to anything the user clicks on, then remove it if the user clicks on it again.

Here is a simple example (uses jQuery):

<ul class="myList">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
  <li>Item 5</li>
</ul>

$("ul.myList li").on("click", function(){
  if($(this).hasClass("selected")){
    $(this).removeClass("selected");   
  } else {
    $(this).addClass("selected");     
  }
});

Demo

Thanks. I’ll try that. How about the actual form submission action?

Did I understand correctly that you want the ids of the selected items to be submitted to a second page via a form?

Yes, that’s correct.

Well you could do that by having a form (obviously) and a hidden input, whose value you change programatically every time a user selects or deselects anything.

$("ul.myList li").on("click", function(){
  if($(this).hasClass("selected")){
    $(this).removeClass("selected"); 
    removeFromForm(this.id);  
  } else {
    $(this).addClass("selected");
    addToForm(this.id)
  }
});

Each element will need its own unique id.
And you’ll need a hidden element in the form.

Why not have a go at writing addToForm yurself.
You can use data properties to store any values on the hidden element.

The selection snippet worked like a charm. Thank you for that.

I am having some trouble with the form. My experience with javascript is very limited, and I clearly do not know what I’m doing here. Would you mind taking a look at the page again? Thank you.

EDIT
page has since been revised, please see below

Okay, I tried, but I really have no idea what I’m doing. Please assist.[code]





  • Fitbit Charge

    $129.95


[/code][code][/code]

Well, building on our previous example, we’ll need a form with a hidden input. We’ll also need to give the elements unique ids:

<form id="myForm">
  <ul class="myList">
    <li id="item_1">Item 1</li>
    <li id="item_2">Item 2</li>
    <li id="item_3">Item 3</li>
    <li id="item_4">Item 4</li>
    <li id="item_5">Item 5</li>
  </ul>
  <input id="selectedItems" name="selectedItems" type="hidden" data-values>
  <button>Submit</button>
</form>

Then, whenever anything is selected or deselected we’ll need to update the value of the hidden input:

function getSelectedItemsAsArray() {
  var items = $("#selectedItems").data("values");
  if (items === ""){
    return []
  } else if (items.match(",")){
    return items.split(",")
  } else{
    return [items];
  }
}

function updateSelectedItems(itemsArray){
  $("#selectedItems").data("values", itemsArray.join());
}

function addToSelectedItems(item){
  var items = getSelectedItemsAsArray();
  items.push(item);
  updateSelectedItems(items);
}

function removeFromSelectedItems(item){
  var items = getSelectedItemsAsArray();
  var index = items.indexOf(item);
  items.splice(index, 1);
  updateSelectedItems(items)
}

$("ul.myList li").on("click", function(){
  if($(this).hasClass("selected")){
    $(this).removeClass("selected");
    removeFromSelectedItems(this.id);
  } else {
    $(this).addClass("selected");
    addToSelectedItems(this.id);
  }
});

This way, when you submit the form POST['selectedItems'] will contain a comma separated list of the ids of whatever was selected.

Here’s a demo. I added a bit of visual feedback as to what POST['selectedItems'] currently contains and I disabled the submit action. Obviously, you can leave this out of your production code.

Hm. Thank you for your work on this. I still can’t seem to get it to work. I made a few minor adaptions.
http://wearabletechforums.com/pages/compare-wearables2/?vs=

Then the best thing to do is to strip down your page so I don’t have to go trawling through lots of code.
Could you please make a page with just three items or so on it?
Please also remove any other content which is not relevant to the problem.

Sure. http://wearabletechforums.com/comparison-sitepoint.html

[code]

<div class="bigBanner">
	<h1>Compare Popular Wearables</h1>
	<span>Select wearables below. Then, <input type="submit" value="click here" id="submit-compareThese"> for a side-by-side comparison.</span>
</div>

<div class="sectionMain compare">
	<div id="wearablesCats">

		<div class="specs-cat"><h3>Compare Fitness Bands</h3></div>
		<ul class="wearablesList" id="fitnessBands">
			<li id="shine">
				<img src="/images/specs-shine.jpg">
				<div class="specs"><h2>Misfit Shine</h2><span class="price">&#36;99.99&#43;</span></div>
			</li>
			<li id="gearFit">
				<img src="/images/specs-gearFit.jpg">
				<div class="specs"><h2>Samsung Gear&nbsp;Fit</h2><span class="price">&#36;149.99&#43;</span></div>
			</li>
		</ul>
		
		<div class="specs-cat"><h3>Compare Other Activity Trackers</h3></div>
		<ul class="wearablesList" id="otherTrackers">
			<li id="one">
				<img src="/images/specs-one.jpg">
				<div class="specs"><h2>Fitbit One</h2><span class="price">&#36;99.95</span></div>
			</li>
			<li id="zip">
				<img src="/images/specs-zip.jpg">
				<div class="specs"><h2>Fitbit Zip</h2><span class="price">&#36;59.95</span></div>
			</li>
			<li id="upMove">
				<img src="/images/specs-upMove.jpg">
				<div class="specs"><h2>Jawbone UP&nbsp;Move</h2><span class="price">&#36;49.99</span></div>
			</li>
		</ul>

	</div>
</div>
/* Template */ body.node77 .titleBar, body.node77 .breadcrumb { display: none; } body.node77 .bigBanner span { display: block; font-size: 16px; } /* Form elements */ #submit-compareThese { -webkit-appearance: none; padding: 1px 6px; font-family: Roboto, 'Helvetica Neue', Arial, sans-serif; font-weight: bold; font-size: 13px; cursor: pointer; cursor: hand; text-transform: uppercase; background-color: @xbHeadingColor; color: #FFF; border: none; margin: 0 5px; } .submit-compareThese:hover { background-color: #F4883D; } /* Categories */ #wearablesCats { word-spacing:-.25em; /* hide whitespace nodes in all modern browsers (not for webkit)*/ display: table; /* Webkit Fix */ padding-right: 0px; } .specs-cat { display: block; background-color: @xbColor1; padding: 10px; margin: 0 0 10px 0; word-spacing: normal; } .specs-cat h3 { display: inline-block; font-size: 16px; font-family: Roboto, "Helvetica Neue", Arial, sans-serif; color: #FFF; font-weight: bold; } /* Items */ .compare ul li { display: inline-block; margin: 0 10px 10px 0; vertical-align: top; background-color: #FFF; box-sizing: border-box; border: 2px solid @xbPrimaryBorder; cursor: pointer; cursor: hand; word-spacing:0; /* reset from parent*/ } @media screen and (min-width: 1151px) { /* Max columns */ .compare #smartwatches li { width: calc(100% / 6 - 11px); } .compare #fitnessBands li { width: calc(100% / 6 - 11px); } .compare #otherTrackers li { width: calc(100% / 6 - 11px); } } @media screen and (max-width: 1150px) { .compare ul li { width: calc(100% / 5 - 11px); } } @media screen and (max-width: 875px) { .compare ul li { width: calc(100% / 4 - 11px); } } @media screen and (max-width: 700px) { .compare ul li { width: calc(100% / 3 - 11px); } } @media screen and (max-width: 525px) { .compare ul li { width: calc(100% / 2 - 11px); } } .compare ul li:hover { border-color: @alertBackground; color: @alertBackground; } .compare ul li:active { border-color: #2D74AF; color: #2D74AF; } .compare ul li.selected { border-color: @alertBackground; color: #FFF; background-color: @alertBackground; } .compare ul li.selected:active { border-color: #2D74AF; background-color: #2D74AF; } .compare ul li img { width: 100%; height: auto; } /* Item checkmark */ .itemPicture { position: relative; } .checkmark { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: none; text-align: center; z-index: 2; } .compare ul li.selected img { visibility: hidden; } /* Item text */ .compare ul li h2 { font-size: 140%; font-face: Roboto, 'Helvetica Neue', Arial, sans-serif; } .compare ul li .specs { margin: 0 10px 5px 10px; } .compare ul li .price { font-size: 120%; } /* Tags */ #popularComparisons { display: block; font-family: 'Roboto', sans-serif; font-size: 13px; } a.tag-compare { display: inline-block; background-color: #7A4CAD; padding: 3px 6px; border-radius: 2px; margin: 4px 4px 0 0; } a.tag-compare:hover { background-color: #8B62B7; text-decoration: none; } .tag-compare span { color: #FFF; } [/code]

Hi,

I was being stupid.
You don’t need to alter the data attribute, you need to order the value of the hidden input itself.
Also, use action="", not url="" and change the method to POST.

That said, here’s an example you can copy and paste:

index.html

<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="utf-8">
    <title>Form demo</title>
    <style>
    /* Template */
    body.node77 .titleBar, body.node77 .breadcrumb {
      display: none;
    }
    body.node77 .bigBanner span {
      display: block;
      font-size: 16px;
    }

    /* Form elements */
    #submit-compareThese {
      -webkit-appearance: none;
      padding: 1px 6px;
      font-family: Roboto, 'Helvetica Neue', Arial, sans-serif;
      font-weight: bold;
      font-size: 13px;
      cursor: pointer; cursor: hand;
      text-transform: uppercase;
      background-color: @xbHeadingColor;
      color: #FFF;
      border: none;
      margin: 0 5px;
    }
    .submit-compareThese:hover {
      background-color: #F4883D;
    }

    /* Categories */
    #wearablesCats {
      word-spacing:-.25em; /* hide whitespace nodes in all modern browsers (not for webkit)*/
      display: table; /* Webkit Fix */
      padding-right: 0px;
    }
    .specs-cat {
      display: block;
      background-color: @xbColor1;
      padding: 10px;
      margin: 0 0 10px 0;
      word-spacing: normal;
    }
    .specs-cat h3 {
      display: inline-block;
      font-size: 16px;
      font-family: Roboto, "Helvetica Neue", Arial, sans-serif;
      color: #FFF;
      font-weight: bold;
    }

    /* Items */
    .compare ul li {
      display: inline-block;
      margin: 0 10px 10px 0;
      vertical-align: top;
      background-color: #FFF;
      box-sizing: border-box;
      border: 2px solid @xbPrimaryBorder;
      cursor: pointer; cursor: hand;
      word-spacing:0; /* reset from parent*/
    }
    @media screen and (min-width: 1151px) { /* Max columns */
      .compare #smartwatches li { width: calc(100% / 6 - 11px); }
      .compare #fitnessBands li { width: calc(100% / 6 - 11px); }
      .compare #otherTrackers li { width: calc(100% / 6 - 11px); }
    }
    @media screen and (max-width: 1150px) {
      .compare ul li { width: calc(100% / 5 - 11px); }
    }
    @media screen and (max-width: 875px) {
      .compare ul li { width: calc(100% / 4 - 11px); }
    }
    @media screen and (max-width: 700px) {
      .compare ul li { width: calc(100% / 3 - 11px); }
    }
    @media screen and (max-width: 525px) {
      .compare ul li { width: calc(100% / 2 - 11px); }
    }
    .compare ul li:hover {
      border-color: @alertBackground;
      color: @alertBackground;
    }
    .compare ul li:active {
      border-color: #2D74AF;
      color: #2D74AF;
    }
    .compare ul li.selected {
      color: #FFF;
      background-color: blue;
    }
    .compare ul li.selected:active {
      border-color: #2D74AF;
      background-color: #2D74AF;
    }
    .compare ul li img {
      width: 100%;
      height: auto;
    }

    /* Item checkmark */
    .itemPicture {
      position: relative;
    }
    .checkmark {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      display: none;
      text-align: center;
      z-index: 2;
    }
    .compare ul li.selected img {
      /*visibility: hidden;*/
    }

    /* Item text */
    .compare ul li h2 {
      font-size: 140%;
      font-face: Roboto, 'Helvetica Neue', Arial, sans-serif;
    }
    .compare ul li .specs {
      margin: 0 10px 5px 10px;
    }
    .compare ul li .price {
      font-size: 120%;
    }

    /* Tags */
    #popularComparisons {
      display: block;
      font-family: 'Roboto', sans-serif;
      font-size: 13px;
    }
    a.tag-compare {
      display: inline-block;
      background-color: #7A4CAD;
      padding: 3px 6px;
      border-radius: 2px;
      margin: 4px 4px 0 0;
    }
    a.tag-compare:hover {
      background-color: #8B62B7;
      text-decoration: none;
    }
    .tag-compare span {
      color: #FFF;
    }
    </style>
  </head>

  <body>
    <form id="compareThese" name="compareThese" action="submit.php" method="POST">
      <input id="vs" name="vs" type="hidden" value="" />

      <div class="bigBanner">
        <h1>Compare Popular Wearables</h1>
        <span>Select wearables below. Then, <input type="submit" value="click here" id="submit-compareThese"> for a side-by-side comparison.</span>
      </div>

      <div class="sectionMain compare">
        <div id="wearablesCats">

          <div class="specs-cat"><h3>Compare Fitness Bands</h3></div>
          <ul class="wearablesList" id="fitnessBands">
            <li id="shine">
              <img src="http://wearabletechforums.com/images/specs-shine.jpg">
              <div class="specs"><h2>Misfit Shine</h2><span class="price">&#36;99.99&#43;</span></div>
            </li>
            <li id="gearFit">
              <img src="http://wearabletechforums.com/images/specs-gearFit.jpg">
              <div class="specs"><h2>Samsung Gear&nbsp;Fit</h2><span class="price">&#36;149.99&#43;</span></div>
            </li>
          </ul>

          <div class="specs-cat"><h3>Compare Other Activity Trackers</h3></div>
          <ul class="wearablesList" id="otherTrackers">
            <li id="one">
              <img src="http://wearabletechforums.com/images/specs-one.jpg">
              <div class="specs"><h2>Fitbit One</h2><span class="price">&#36;99.95</span></div>
            </li>
            <li id="zip">
              <img src="http://wearabletechforums.com/images/specs-zip.jpg">
              <div class="specs"><h2>Fitbit Zip</h2><span class="price">&#36;59.95</span></div>
            </li>
            <li id="upMove">
              <img src="http://wearabletechforums.com/images/specs-upMove.jpg">
              <div class="specs"><h2>Jawbone UP&nbsp;Move</h2><span class="price">&#36;49.99</span></div>
            </li>
          </ul>

        </div>
      </div>
    </form>

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.js"></script>
    <script>
      function getSelectedItemsAsArray() {
        var items = $("#vs").val();
        if (items === ""){
          return []
        } else if (items.match(",")) {
          return items.split(",")
        } else {
          return [items];
        }
      }
      function updateSelectedItems(itemsArray) {
        $("#vs").val(itemsArray.join());
      }
      function addToSelectedItems(item) {
        var items = getSelectedItemsAsArray();
        items.push(item);
        updateSelectedItems(items);
      }
      function removeFromSelectedItems(item) {
        var items = getSelectedItemsAsArray();
        var index = items.indexOf(item);
        items.splice(index, 1);
        updateSelectedItems(items)
      }
      $("ul.wearablesList li").on("click", function() {
        if($(this).hasClass("selected")){
          $(this).removeClass("selected");
          removeFromSelectedItems(this.id);
        } else {
          $(this).addClass("selected");
          addToSelectedItems(this.id);
        }
      });
    </script>
  </body>
</html>

submit.php

<?php
  print_r($_POST);

I will try this tonight. Thank you. Also, I wish to use the GET method. Are you merely suggesting I use POST or saying this will not work unless I use POST? If the latter, I will need to modify the code so that GET is possible. Thanks.

No, GET will work, too.
It might actually make more sense, as that way people can bookmark comparisons.

It worked! Thank you very much. Is this fully compatible with all modern browsers?

Also, the URL string is ?vs=watch%2Cgear2Neo%2Cpebble%2CgearS%2Cactivite
Is this correct for an array?

One more thing. Sorry about this. Is it possible to sort the items alphabetically? For analytics purposes, it would be important that the URL be the same whenever the selections are the same—even when they are selected in a different order.

Ok, we have a bug. I clicked a DIV multiple times on and off, and ended up with duplicates (peak):
?vs=peak%2Csurge%2Cpeak%2Cwatch