Change URL based on change of dynamic select box - javascript

I have a select box populated from a JSON file, I want to reload the URL but pass the value from the select box.
Here is a cut down version of my index.html file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Timetables</title>
<!-- Bootstrap -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div id="navbar" class="navbar-collapse collapse">
</div>
<!--/.navbar-collapse -->
</div>
</nav>
<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
<div class="container">
<div id="headerArea">
</div>
</div>
</div>
</body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
var $crs = GetURLParameter('crs');
// Function that uses this variable removed as not relevant
$.getJSON('csr.json', function (data) {
var stationDropdown = '<form class="navbar-form navbar-right" action="">';
stationDropdown += '<select class="form-control" id="stations">';
for (var i in data) {
stationDropdown += '<option value="' + data[i].Code + '">' + data[i].StationName + '</option>';
}
stationDropdown += '</select>';
stationDropdown += '</form>';
$("#navbar").html(stationDropdown);
});
$(function(){
// bind change event to select
$('#stations').bind('change', function () {
var url = $(this).val(); // get selected value
if (url) { // require a URL
window.location = 'index.html?crs='.url; // redirect
}
return false;
});
});
</script>
</html>
and here is a sample of the JSON
[
{
"StationName":"Abbey Wood",
"Code":"ABW"
},
{
"StationName":"Aber",
"Code":"ABE"
}
]
The select box generates fine and is 'injected(?) into the navbar div, but the on change event wont register
Basically if someone was to select Aber, the onchange event will reload index.html?crs=ABE automatically.
Dev tools is not throwing up any errors, its just not doing anything when I change the select box.
I suspect I need to run the on change event as a function that is called exclusively when needed as putting it in at the bottom of the index.html file means its loading before the DOM is ready?
Thanks in advance for any assistance.

You should move all of your HTML building INTO the HTML.
Inside of your getJSON() you can cut that code down to this:
var stations = $( '#stations' );
for (var i in data) {
stations.append( '<option value="' + data[i].Code + '">' + data[i].StationName + '</option>' );
}
Once you do that, everything else should work appropriately. Here's what I changed in your HTML:
<div id="navbar" class="navbar-collapse collapse">
<form class="navbar-form navbar-right" action="">
<select class="form-control" id="stations">
<option>Select One</option>
</select>
</form>
</div>
Also, as a note. jQuery recommends using the on() method instead of the bind() method as of 1.7.
http://api.jquery.com/bind/

Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the event binding call.
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time.
As you are creating elements dynamically.
You need to use Event Delegation. You have to use .on() using delegated-events approach.
General Syntax
$(document).on(event, selector, eventHandler);
Ideally you should replace document with closest static container.
Example
$("#navbar").on('change', '#stations', function(){
//Your code
});

Always the same question... you initiate your bind event before the dropdown is created, because it depends on an ajax call.
What's wrong with your code :
$.getJSON('csr.json', function (data) { // This is done #1
.......
$("#navbar").html(stationDropdown); // this is done #3 : creating #stations.
});
$('#stations').bind('change', function () { // This is done #2 and won't do anything because #stations doesn't exist yet
........
});
The right way is :
$.getJSON('csr.json', function (data) { // This is done #1
.......
$("#navbar").html(stationDropdown); // this is done #2 : creating #stations.
$('#stations').bind('change', function () { // This is done #3
........})
});

It's because the $.getJSON function is called after the $(function(){
If you move the code in $(function(){, to the end of the $.getJSON function, then it'll work.

You need to use on for dynamic content:
$('#navbar').on('change', '#stations', function () {
^ Static container content is appended to
^ #stations = target element

Related

JQuery parent selector and fadeout

I'm trying to make a simple ToDo list in JQuery and I run into a problem.
I made function 'deleteListItem' and I use it to delete my lists items with:
$(this).parent().remove();
, and then I wanted to add fadeOut effect to my list and so I tried:
$(this).fadeOut(1000, function(){
$(this).parent().remove();
})
, but this fadesOut just my delete button so then I tried
$(this).parent().fadeOut(1000, function(){
$(this).parent().remove();
})
and this fades all of my 'ul' instead of just 'li' element.
Here is mine JSBIN so you better understand what I'm doing: http://jsbin.com/ciyufi/edit?html,js,output
Inside the callback handler, this refers to the <li>.
$(this).parent().fadeOut(1000, function(){
$(this).remove();
})
// This is where I put my functions
// This function adds items on our list
function addListItem() {
var text=$('#newText').val(); // val returns any text thats inside input
$('#todoList').append('<li><input type="checkbox" class="done">'+ text +'<button class="delete">Delete</button></li>');
$('#newText').val(''); // this is added so that our input deletes previous text when add is clicked
};
// This function deletes items on our list
function deleteListItem() {
// In order to delete entire list item we have to use parent method > without parent method we would only delete our delete button
$(this).parent().fadeOut(1000, function(){
$(this).closest("li").remove();
})
};
// This function adds checked remark on our item list
function itemDone() {
// First we check if our element has textDecoration="line-through"
// If it has it second line deletes it
// And our else statement allows as to add it again
if ($(this).parent().css('textDecoration') == 'line-through') {
$(this).parent().css('textDecoration', 'none');
} else {
$(this).parent().css('textDecoration', 'line-through');
}
}
$ (document).ready(function(){
$('#add').on('click', addListItem); // This is for button to add text
// This part enables us to add text on pressing enter key
$( "#newText" ).keypress(function( event ) {
if ( event.which == 13) {
addListItem();
}
});
// $('.delete').on('click', deleteListItem);
// $('.done').on('click', itemDone);
// Lines above don't work because we are adding elements after page loads
// In above lines browser didn't bind functions to our new elements because it didn't see them at the time
// In order to make it work we add document selector > its not the best solution but i'm not good enough for better
// We don't need to do it for #add because its already on page
$(document).on('click', '.delete', deleteListItem);
$(document).on('click', '.done', itemDone);
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>ToDo Lista</title>
<!-- Bootstrap -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/main.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto+Slab" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<section class="container">
<h1>ToDo List</h1>
<ul id="todoList">
<li><input type="checkbox" class="done"> Clean House <button class="delete">Delete</button></li>
<li><input type="checkbox" class="done">Buy Milk <button class="delete">Delete</button></li>
<input id="newText" type="text" placeholder="Write Your Task"><button id="add">Add</button>
</ul>
</section>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>
I prefer to use closest. closest Just change 'deleteListItem' function to remove closest li item on delete.
function deleteListItem() {
// In order to delete entire list item we have to use parent method > without parent method we would only delete our delete button
$(this).parent().fadeOut(1000, function(){
$(this).closest("li").remove();
})
};

Knockout JS `hasFocus` within template that is called twice

I have a template, which is using hasFocus similar to example in docs: http://knockoutjs.com/documentation/hasfocus-binding.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>field test</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/bootstrap/3.3.6/css/bootstrap.min.css">
<style>
body {
margin-top: 1em;
}
</style>
<script src="https://cdn.jsdelivr.net/g/jquery#2.2.2,bootstrap#3.3.6,knockout#3.4.0"></script>
<script>
$(function() {
var VM = function() {
var model = {};
model = {
one: ko.observable(false),
two: ko.observable(false)
};
this.model = model;
};
ko.applyBindings(new VM());
});
</script>
</head>
<body>
<script type="text/template" id="first-template">
<input type="text" class='form-control' data-bind="hasFocus: model.one">
<p>one has<span data-bind="visible: !model.one()"> not got</span> focus now</p>
<input type="text" class='form-control' data-bind="hasFocus: model.two">
<p>two has<span data-bind="visible: !model.two()"> not got</span> focus now</p>
</script>
<div class="container">
<div class="row">
<div class="col-sm-12">
<div data-bind="template: { name: 'first-template' }"></div>
<!-- if I uncomment the next line, it stops working... -->
<!-- <div data-bind="template: { name: 'first-template' }"></div> -->
</div>
</div>
</div>
</body>
</html>
It all works as expected, updating the focus state on the model correctly when entering and leaving the field. However, if I apply the template a second time, the template appears to work ok with the exception of the focus state. Is this unsupported, or am I implementing wrong? How can I use template multiple times, and still use focus state?
The browser cannot have two <input> elements with focus. The hasFocus bind will try to give both elements a focused state. You can circumvent this behavior by using event bindings for both focus and blur events:
data-bind="event: {
focus: function() {
model.one(true)
},
blur: function() {
model.one(false)
}
}"
Check out this fiddle for a working example of your code: https://jsfiddle.net/77meefmf/
You need to make sure each copy of the template has its own viewmodel. The hasFocus binding is meant to represent the focus status a single field. If you bind it to more then one field, the results will be wrong.

Handlebarsjs : H1 tag won't display when submit button is clicked

I'm messing around with Handlebars.js and I'm doing a very simple example consisting of a tutorial from a website(the shoes section) and my own simple little template(the heading, where the problem is)
handlebardemo.html
<head>
<meta charset="ISO-8859-1" name="viewport" content="width=device-width, initial-scale=1">
<title>Handlebar demo</title>
<script src="lib/jquery-2.1.4.js" type="text/javascript"></script>
<script src="lib/jquery-ui.js" type="text/javascript"></script>
<script src="lib/handlebars-v4.0.4.js" type="text/javascript"></script>
<script src="js/main.js" type="text/javascript"></script>
<link rel="stylesheet" href="css/w3.css">
<link rel="stylesheet" href="css/jquery-ui.css">
</head>
<body>
<div class="username-container">
<script id="heading-template" type="x-handlebars-template">
<h1 class="h1">Hello {{username}}</h1>
</script>
<input type="text" id="username">
<button type="submit" id="username-submit">Enter</button>
</div>
<h4 class="w3-row-padding">Shoe List:</h4>
<ul class="shoesNav w3-ul w3-text-indigo"></ul>
<script id="shoe-template" type="x-handlebars-template">
{{#each this}}
<li class="shoes">{{name}}--Price:{{price}} </li>
{{/each}}
</script>
</body>
main.js
$("#username-submit").click(function(){
var uNameVal = $("#username").val();
var uName = {"username":uNameVal};
var theTemplateScript = $("#heading-template").html();
var theTemplate = Handlebars.compile(theTemplateScript);
$(".username-container").append(theTemplate(uName));
});
$(function (){
var shoesData=[{name:"Nike", price:199.00}, {name:"Loafers", price:59.00}, {name:"Wing Tip", price:259.00}];
//Get html from tempalte in script tag
var theTemplateScript = $("#shoe-template").html();
//Compile the template
var theTemplate = Handlebars.compile(theTemplateScript);
$(".shoesNav").append(theTemplate(shoesData));
//shoesData is passed to compiled handlebars function
//function inserts values from the objects in their respective places in the HTML
//and returned HTML: as a string. Then jQuery is used to append the resulting HTML string to the page
})
Im not sure if I'm using the handlbars syntax etc. correctly, but i based it mostly off of the second function in main.js, which came from a brief handlebars tutorial
When I click the Enter button, nothing happens. There are no console errors, it just does nothing. Am I going about this the wrong way, at least compared to the unordered list example?
EDIT: As per Elli Parks answer, I added an id to the submit button and changed the click handler assignment to the submit button rather than the textbox(a silly mistake on my part). The element still won't appear when the submit button is clicked
In main.js, you're attaching the click handler to #username, which is an input field. You need to give the Enter button an id (ex: #username-submit) and attach the click handler to the button.
So something like this:
handlebardemo.html
<button type="submit" value="Enter" id="username-submit" >Enter</button>
main.js
$("#username-submit").click(function(){
var uNameVal = $("#username").val();
var uName = {"username":uNameVal};
var theTemplateScript = $("#heading-template").html();
var theTemplate = Handlebars.compile(theTemplateScript);
$(".username-container").append(theTemplate(uName));
});
You need to change two things:
fix the selector to target the button, like #ElliPark has already said
put the whole thing into the document-ready handler (ie, into the $(function () {...} ); construct. You are trying to attach the event listener before the DOM is ready.
See the demo on JSBin.

addEventListner working only at app creation

For some reason my eventHandling code stopped working.
I was working on some functions to handle the indexedDB stuff, when i went back to work on the interface, i noticed that the eventHandlers only worked at app creation, even when i didnt performed any action on them, they just go off.
Heres my default.js
(function () {
"use strict";
WinJS.Binding.optimizeBindingReferences = true;
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
var _swAlarm;
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
} else {
}
args.setPromise(WinJS.UI.processAll());
}
};
app.oncheckpoint = function (args) {
};
function testSelection(value) {
console.log("from event listner "+value)
}
function getDomElements() {
_swAlarm = document.getElementById("swAlarm");
}
function registerHandlers() {
_swAlarm.addEventListener("onchange", console.log("ola"));
}
app.onready = function () {
getDomElements();
registerHandlers();
}
app.start();
And this is my default.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>MyApp</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<!-- my references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
<script src="/js/database.js"></script>
<!-- jquery references -->
<script src="js/jquery-1.8.2-win8-1.0.js"></script>
<script src="js/visualize.jQuery.js"></script>
<script type="text/javascript"> jQuery.isUnsafe = true;</script>
<link href="/css/default.css" rel="stylesheet" type="text/css">
</head>
<body>
<div id="content">
<div id="settings">
<h2 id="lAlarm">Alarm</h2>
<div id="swAlarm" data-win-control="WinJS.UI.ToggleSwitch" ></div>
<input id="iMaxval" type="number">
<input id="iMinval" type="number">
<button id="bSave">Save</button>
</div>
<div id="graph">
<h2 id="hGraph" class="graph">Graph</h2>
</div>
<div id="stats">
<h2 id="hStats" class="stats">Stats</h2>
</div>
</div>
</body>
</html>
When you run this code:
_swAlarm.addEventListener("onchange", console.log("ola"));
you are:
running console.log("ola")
affecting the result as a callback for the event onchange of _swAlarm.
This is wrong on many levels.
console.log("ola") does not return a call back. I think I understand what you meant, and the correct code could be: function() { console.log("ola"); }
When using addEventListener you have to use dom lexique with event denomination. In your case, onchange needs to be instead change. If you had to affect this event directly in html, you indeed would have to use onchange="console.log("ola");". But not with addEventListener.
The final result is:
_swAlarm.addEventListener("change", function() { console.log("ola"); }, false);
As for why was it working on app creation, I think it is simply because on app creation console.log("ola") was called right away at event affectation, but since no event was actually affected later on you would not get any result for the onchange event.
On a side note, and since I guess you're sort of migrating from "old" syntaxis (onchange... etc.) to the addEventListener api, I'll add an important difference between the 2 modes: when an event is executed the old way, this referers to window. But affecting the callback through addEventListener makes the domElement itself (_swAlarm in your case) be the target of this during the callback execution.

Dynamically add jquery mobile components to listview with formatting

When I'm dynamically inserting the following code, I can force the page to refresh so it applies the jQuery mobile formatting.
For some reason its doesn't allow me to set the button formatting. Its really odd, because it allows the list to be dynamically inserted and the button, but i cant seem to format the button except for the name.
It can be manipulated via CSS but I want to use the jQuery API.
$('#cartList').append('<li>'
+ '<h3>' + game.Title+'</h3>'
+ '<p>' + '£' + game.Price + '</p>'
+ 'Remove'
+ '<h3 class="ui-li-aside">' + game.Format + '</h3>'
+ '</li>').trigger("create");
The jQuery Mobile Doc mentions that if new list items are added to the list or removed from it, the dividers are not automatically updated and you should call refresh() on the listview to redraw the autodividers.
Try to add: $('#cartList').listview('refresh'); after you have populated the list.
Example:
<!doctype html>
<html lang="en">
<head>
<title></title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.1/jquery.mobile-1.1.1.min.css" />
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.1.1/jquery.mobile-1.1.1.min.js"></script>
<script>
$(document).ready(function(){
$("#add-li-button").click(function(){
$('#listList').append("<li data-role=\"collapsible\"> <h3>New List</h3> <div data-role=\"fieldcontain\"></div> </li>").listview("refresh");
});
});
</script>
</head>
<body>
<div data-role="page" id="page">
<ul id="listList" data-role="listview">
</ul>
<input type="button" id="add-li-button" value="add a checkbox to list1" />
</div>
</body>
</html>

Categories

Resources