I have two drop down that can be manipulate. The second drop down; httpauthmode is manipulated by the value in the first drop down;httprestype.
I want the second drop down; httpauthmode to change to default value when user selected
httpreqtype() == 2; i.e
<option value="0" selected="selected">None</option>
//I want the value = 0 be the default value
Javascript
_self.httpreqtype = ko.observable( httpreqtype );
_self.httpauthmode = ko.observable(null);
Here is my html
<label>HTTP Request Type</label><br/>
<select data-bind="value: httpreqtype" style="width:200px">
<?php
foreach($httpRequestOptions as $key=>$val) {
echo '<option value="'.$val["id"].'" >'.$val["name"].'</option>';
};
?>
//$httpRequestOptions is an array inside my viewModel, I only put a piece of my code
</select>
<label>HTTP Auth Type</label><br />
<select data-bind="value: httpauthmode" style="width:200px">
<option value="0" selected="selected">None</option>
<option value="1">Basic Authentication</option>
<option value="2" data-bind = "visible: httpreqtype() == 2" >Body Encryption</option>
<option value="3" data-bind = "visible: httpreqtype() == 2" >Basic Authentication + Body Encryption</option>
</select>
I try hours googling and already tried subscribe function, set the observable to (null), ("") and many other ways. Can someone expert help me or maybe suggest what method I can try. Really appreciate it and many thanks in advance.
You should approach this very differently. Carefully read the options binding documentation and try to rework your code to that approach. Basically it allows you to data bind the select tag, and have the options rendered dynamically by Knockout.
Something like this:
var Model = function(httpreqtype){
var _self = this;
_self.httpauthmode = ko.observable(null);
_self.httpreqtype = ko.observable( httpreqtype );
_self.httpauthmode = ko.observable(null);
var mode0 = { id: 0, txt: "None" };
var mode1 = { id: 1, txt: "Basic Authentication" };
var mode2 = { id: 2, txt: "Body Encryption" };
var mode3 = { id: 3, txt: "Basic Authentication" };
_self.availableHttpAuthModes = ko.computed(function() {
if (_self.httpreqtype() == 2) {
return [mode0, mode1];
}
return [mode0, mode1, mode2, mode3];
});
}
ko.applyBindings(new Model(2));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<select data-bind="value: httpauthmode,
optionsText: 'txt',
options: availableHttpAuthModes" >
</select>
<br /><br />Change httpreqtype:
<br /><input data-bind="value: httpreqtype, valueUpdate: 'afterkeydown'" />
Set httpauthmode to '0' (value of None) when httprestype changes to '2':
_self.httprestype.subscribe(function(value) {
if(value === '2') {
_self.httpauthmode('0');
}
});
JSFiddle
Related
I am working on a form with multiple drop down options.
I stripped everything down to three questions in the form below, to illustrate my issue.
I have tried this code (and a few variations):
function update_variables(el, standard_val, var_list) {
standard_val.value = var_list[el.getElementsByTagName('option')[el.selectedIndex].value];
}
var select2 = document.getElementById('think_question'),
hidden_answer = document.getElementsByName('thought_goes_here')[0];
var why_options = {
'yes': '',
'no': 'Well, you tried.'
};
select2.addEventListener('change', function() {
update_variables(select2, hidden_answer, why_options);
});
var sel_group_control = document.getElementById('follower_question');
var sel_free_will = document.getElementById('think_question');
sel_group_control.addEventListener('change', answer_bypass);
function answer_bypass() {
var user_choice = sel_group_control.value;
if (user_choice === 'no') {
sel_free_will.selectedIndex = 2;
sel_free_will.style.backgroundColor = "#D3D3D3";
sel_free_will.disabled = true;
}
}
<h2>Life Decisions</h2>
<form>
Be exactly like everone else?
<select id='follower_question'>
<option disabled selected value> -- select an option -- </option>
<option>yes</option>
<option>no</option>
</select>
<br> Think for yourself?
<select id='think_question'>
<option disabled selected value> -- select an option -- </option>
<option>yes</option>
<option>no</option>
</select>
<br> Original thought:<input name="thought_goes_here" size="50" value="" id="your_thoughts">
</form>
If question 2 is set to 'no' then the answer to question 3 is known and filled in with a response. If question 1 is 'no' then question 2 should be set to 'no' and read-only. I expected question 3 to be updated automatically too when choosing 'no' in response to question 1 but that function seems to be ignored.
You need to register an event to trigger the second select change.
Like so:
function answer_bypass() {
var user_choice = sel_group_control.value;
if (user_choice === 'no') {
sel_free_will.selectedIndex = 2;
sel_free_will.style.backgroundColor = "#D3D3D3";
sel_free_will.disabled = true;
// Create a new 'change' event
var event = new Event('change');
// Dispatch it.
select2.dispatchEvent(event);
}
}
A page deals with an input field that changes behavior depending on the dropdown value.
<div class="form-group">
<label for="exampleInputEmail2">Element Name</label>
<select class="form-control" name="element_id" id="element_name">
#foreach($elements as $element)
<option value="{{ $element->element_id }}">{{ $element->element_name }}</option>
#endforeach
</select>
</div>
<div class="form-group">
<label for="exampleInputName2">Element Value</label>
<input type="text" class="form-control" id="element_value" name="value" placeholder="Add an Element Value">
</div>
A script I have is below:
<script type="text/javascript">
<?php
echo "var javascript_array = ". $list . ";\n";
?>
$("#element_name").on('change', function(){
var id_input = $('#element_name').val();
if(id_input == 2){
$("#element_value").datepicker();
}
else if(jQuery.inArray(id_input, javascript_array)!='-1'){
$("#element_value").datepicker('destroy');
$( function() {
$("#element_value").autocomplete({
scroll: true,
autoFocus: true,
minLength: 3,
source: function( request, response ) {
$.ajax({
url: "/employees/public/admin_list/search",
dataType: "json",
data: {
searchText: request.term
},
success: function( data ) {
response($.map(data, function(item) {
return {
label: item.name,
value: item.id
};
}));
}
});
},
select: function( event, ui) {
$(this).val(ui.item.label);
return false;
}
} );
} );
}
else {
$('#element_value').datepicker('destroy');
}
});
</script>
So basically, if the value of the dropdown is 2(Birthday), the field changes to datepicker (which works), unfortunately, the part where else if(jQuery.inArray(id_input, javascript_array)!='-1') doesn't seem to work, as it doesn't change the input to a search input. (If I hardcode it to else if((id_input == 1) || (id_input == 4) || (id_input == 5)) it always works, but this list ids will increase as users creates them in the future, so I have to store them in javascript_array and just search from there).
What am I missing?
the array shows as
var javascript_array = [1,4,5];
generated from a controller as below:
$lists = Elements::select('element_id')->where('is_list', 1)->get();
foreach ($lists as $r){
$list_temp[] = $r->element_id;
}
$list = json_encode($list_temp);
the issue is jQuery.inArray must be passed the correct type.
$('#element_name').val() would set id_input as a string:-
var id_input = "4";
var javascript_array = [1,4,5]
var stringType = jQuery.inArray(id_input, javascript_array);
console.log(stringType); // -1
var intType = jQuery.inArray(parseInt(id_input), javascript_array);
console.log(intType); // 1
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
so you need to parseInt the dropdown value.
an input field that changes behavior depending on the dropdown value.
If I have understood correctly, then you can achieve this in a single-line jQuery function:
$(document).ready(function(){
$('select').change(function(){
$('input').attr('type', $('option:selected').val());
})
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select>
<option value="text">Text Input</option>
<option value="button">Button Input</option>
<option value="date">Date Input</option>
<option value="checkbox">Checkbox Input</option>
<option value="radio">Radio Input</option>
</select>
<input type="text" />
I have a java / Spring MVC application that includes forms that interface with tables. On one of the pages, I have designed it so that when a row is clicked on the table, form data is populated using the data that is in that row.
Javascript code:
$('#table tbody').on('click', 'tr', function () {
var idx = table.row(this).index();
var vName = document.getElementById("userName");
vName.value = table.cell(idx, 7).data();
This works well for the text form fields. Where I am running into a problem is in the "userName" field, since that is a list (form:select) field.
I'm not really sure how I would go about the process of having my app be able to locate the list index of a name in the dropdown list based on the text data that it is reading from the table.
Here is the html for the dropdown field:
<spring:bind path="model.userName">
<label for="fullName">Select User:</label>
<form:select cssClass="form-control" path="model.userName" id="userName" name="userName">
<form:option value=""></form:option>
<form:options items="${userList}" itemLabel="fullName" itemValue="ID"/>
</form:select>
</spring:bind>
The dropdown list, ${userList}, is created by building a List in my DAO, along with the following RowMapper method:
private static class UserRowMapper implements RowMapper {
public Object mapRow(ResultSet rs, int i) throws SQLException {
return new Users(rs.getLong("ID"),
rs.getString("LNAME") + ", " + rs.getString("FNAME"));
}
}
When you set a value of a select element, in fact you are setting the option with this value as selected, while here you are using the name so you are dealing with the content of the option and not it's value.
So in your example when you have the selected userName from your table you just need to loop through the select options and set the appropriate option as selected.
This is the code you need:
$('#table tbody').on('click', 'tr', function() {
var idx = table.row(this).index();
var vName = document.getElementById("userName");
for (i in vName.options) {
//I test on the innerText here because FF doesn't support it
var optionText = typeof vName.options[i].innerText !== 'undefined' ? vName.options[i].innerText : vName.options[i].textContent;
if (optionText === table.cell(idx, 7).data()) {
vName.selectedIndex = i;
break;
}
}
});
This is a brief Snippet Example:
$('#name').on('change', function() {
var vName = document.getElementById("userName");
for (i in vName.options) {
var optionText = typeof vName.options[i].innerText !== 'undefined' ? vName.options[i].innerText : vName.options[i].textContent;
if (optionText === $(this).val()) {
vName.selectedIndex = i;
break;
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Enter name:
<input type="text" id="name" />
<select name="userName" id="userName">
<option value="">Muhammad</option>
<option value="">Alain</option>
<option value="">John</option>
<option value="">Ali</option>
<option value="">Maria</option>
<option value="">Lee</option>
<option value="">Alessandro</option>
</select>
Usually the best way to get data from a server to the front end is as a JSON string/object then we can easily manipulate that just like you're doing already.
I think you're pretty much there you're just missing one part.
In this below example i'm listing the same users in a table and menu and on click of the table row the selected user in the drop down is defaulted.
For example with this sample table data.
JS:
var users = [{
ID: 0,
LNAME: "First",
FNAME: "Senior"
}, {
ID: 1,
LNAME: "Second",
FNAME: "Sir"
}, {
ID: 2,
LNAME: "Third",
FNAME: "Chap"
}, {
ID: 3,
LNAME: "Fourth",
FNAME: "Mr"
}];
mag.module('userName', {
view: function(state) {
state.tr = state.option = users.map(function(user) {
return {
_selected: user.ID == state.index ? true : null,
_text: user.FNAME + ' ' + user.LNAME,
_value: user.ID
}
});
state.$tr = {
_onclick: function(e, i) {
state.index = i;
state.span = users[i].FNAME + users[i].LNAME
}
}
}
});
HTML:
<div id="userName">
<table>
<tr></tr>
</table>
<hr/>
<label for="fullName">Select User: <span></span></label>
<select class="form-control" name="userName">
<option></option>
</select>
</div>
Here is the full working example: http://jsbin.com/bokiqebezo/1/edit?html,js,output
Hope this helps!
My problem is that i have 2 dropdowns and I want to change second dropdown by the value of first. For example: if user chooses "Apple" on the first dropdown second dropdown should instantly get "iPhone" and "iPad" options. If client changes his mind and selects "Microsoft" "iPhone" and "iPad" values should be deleted and instead of them there should appear "Windows" and "Office". How can I make it work? Thanks.
HTML:
<select name="brand" id="brand" onChange="populateSecond(this.value);">
<option value="">----------------</option>
<option value="1">Apple</option>
<option value="2">Microsoft</option>
</select>
<select id="model">
<option value="">----------------</option>
</select>
jQuery:
$(document).ready(function() {
$("#brand").change(function(populateSecond(id)) {
if(id == 1){
$('select[id=model]').append('<option value="a">iPhone</option>');
$('select[id=model]').append('<option value="a">iPad</option>');
}if(id == 2){
$('select[id=model]').append('<option value="b">Windows</option>');
$('select[id=model]').append('<option value="b">Office</option>');
}
});
});
Problem: http://jsfiddle.net/w6E88/6/
Remove the onChange from the html and do it like this!You are already using Jquery onchange no need to give onChange to your HTML also if you need the selected value from the first dropdown you could simply use this.value to get it and make the necessary changes to your Second DropDown List.
HTML
<select name="brand" id="brand">
<option value="">----------------</option>
<option value="1">Apple</option>
<option value="2">Microsoft</option>
</select>
<select id="model">
<option value="">----------------</option>
</select>
JQUERY
$(document).ready(function() {
$("#brand").change(function() {
var id=this.value;
if(id == 1){
$('#model').html("");
$('#model').append('<option value="a">iPhone</option>');
$('#model').append('<option value="a">iPad</option>');
}else if(id == 2){
$('#model').html("");
$('#model').append('<option value="b">Windows</option>');
$('#model').append('<option value="b">Office</option>');
}
else{
$('#model').html("");
$('#model').append('<option value="">----------------</option>')
}
});
});
Here is another jQuery way of achieving the functionality you want (commented with explanation)
Added bootstrap class to select element for the looks.
HTML
<select id="mainCategorySelect" name="mainCategorySelect" class="form-control">
<option>Select category</option>
</select>
<select id="subCategorySelect" name="subCategorySelect" class="form-control"></select>
JS
// Wait for the dom to be ready
$(function () {
// For the sake of this example our business and products are arrays
var businesses = ["Microsoft","Apple"],
msProducts = ["Microsoft Phone","Microsoft Office","Microsoft Windows 10"],
appleProducts = ["Apple iPhone","Apple iPad","Apple iPod","Apple iSomething"],
// Declare variables for the select elements
mainCategorySelect = $('#mainCategorySelect'),
subCategorySelect = $('#subCategorySelect');
// Iterate thorugh businesses and populate the main select element
for (var i = 0; i < businesses.length; i++) {
mainCategorySelect.append("<option value='"+businesses[i]+"'>"+businesses[i]+"</option>");
}
// using jQuery .on('change')
mainCategorySelect.on('change', function() {
// Always clear the sub category select when main select element value is changed
subCategorySelect.empty();
// Retrieve the value of the main select element
var business = $(this).val();
// if else statement to deside which products to list in the sub category select element
if (business == "Microsoft") {
// if Microsoft then iterate through the msProducts array and append the values as option elements to the sub category select element
for (var i = 0; i < msProducts.length; i++) {
subCategorySelect.append("<option value='"+msProducts[i]+"'>"+msProducts[i]+"</option>");
}
} else if(business == "Apple") {
// if Apple then iterate through the appleProducts array and append the values as option elements to the sub category select element
for (var i = 0; i < appleProducts.length; i++) {
subCategorySelect.append("<option value='"+appleProducts[i]+"'>"+appleProducts[i]+"</option>");
}
}
// When the user changes the value of the sub category select element the do something with it
subCategorySelect.on('change', function() {
alert($(this).val());
});
});
});
And here is a working fiddle: http://jsfiddle.net/kagLhpka/
You already have onChange="populateSecond(this.value);" in your HTML code, no need for the .change in JS as well.
You can either define the function populateSecond entirely before the first call to it; or use only the jQuery method. I'm giving the jQuery result here only:
$(document).ready(function () {
$("#brand").on('change', function (id) {
if (id == 1) {
$('select[id=model]').append('<option value="a">iPhone</option>');
$('select[id=model]').append('<option value="a">iPad</option>');
} else {
$('select[id=model]').append('<option value="b">Windows</option>');
$('select[id=model]').append('<option value="b">Office</option>');
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select name="brand" id="brand">
<option value="">----------------</option>
<option value="1">Apple</option>
<option value="2">Microsoft</option>
</select>
<select id="model">
<option value="">----------------</option>
</select>
PS: I prefer using .on('change', handler) method over .change.
Here is the structured way.
var childData = {
apple: ["iPhone", "iPad"] ,
ms: ["Windows", "Office"]
};
$("#brand").change(function () {
var newData = childData[this.value];
var element = $("#model").empty();
element.append('<option>----------------</option>');
$.each(newData, function(i, val) {
element.append('<option value='+i+'>'+val+'</option>');
});
});
Check this Fiddle: http://jsfiddle.net/soundar24/w6E88/11/
Using explicit conditionals to validate against will make this difficult to maintain in the future if the product line expands beyond a certain quantity. Using some form of array is a better way to do it, as others have shown.
Also, while jQuery is a great library, don't forget about vanilla JavaScript. When coded well, even though it appears more convoluted, plain JavaScript should run faster than a jQuery counterpart. With that in mind, here's another solution, this time in "more or less" plain JavaScript -- I left in the on ready.
HTML
<select name="brand" id="brand">
<option value="-1">--------------------</option>
<option value="apple">Apple</option>
<option value="microsoft">Microsoft</option>
</select>
<select id="model">
<option value="-1">--------------------</option>
</select>
JavaScript
var products = {
apple: [
{ name: "iPhone 6 Plus", model: "iphone_6plus" },
{ name: "iPhone 6", model: "iphone_6" },
{ name: "iPhone 5s", model: "iphone_5s" },
{ name: "iPhone 5c", model: "iphone_5c" }
],
microsoft: [
{ name: "Windows 10", model: "windows_10" },
{ name: "Windows 8", model: "windows_8" },
{ name: "Office 2015", model: "office_2015" },
{ name: "Office 2014", model: "office_2014" }
]
};
function create_option(text, value) {
var option = document.createElement("option");
var txt = document.createTextNode(text);
option.value = value;
option.appendChild(txt);
return option;
}
function populate_model(selection) {
var select = document.getElementById("model");
var i, l;
if ((selection == -1) || (products[selection] === undefined))
return false;
while (select.lastChild)
select.removeChild(select.lastChild);
select.appendChild(document.createElement("option").appendChild(document.createTextNode("--------------------")));
for (i = 0, l = products[selection].length; i < l; i++)
select.appendChild(create_option(products[selection][i].name, products[selection][i].model));
}
$(document).ready(function() {
var brand = document.getElementById("brand");
brand.onchange = function() {
populate_model(this.options[this.selectedIndex].value);
};
brand.value = -1;
});
I've updated your JSFiddle as well: http://jsfiddle.net/w6E88/13/
So I have never really used Knockout before so I'm very new to this.
The pre-existing knockout means that when a certain value is clicked on a dropdown a certain list of values become available to select in the next dropdown. I'm now adding a second value to the first list which changes the values in the second dropdown. These dropdown values are all imported from 2 different sharepoint lists.
$.when(
$.getJSON('../_vti_bin/listdata.svc/ApplicationList?$select=Id,ApplicationName,ApplicationDescription'),
$.getJSON('../_vti_bin/listdata.svc/ApplicationRoleList?$select=ApplicationID,RoleID,RoleNameValue,Description,PrivilegedValue')
).then(function(apps, roles){
// both ajax calls are finished now
var rolesMap = {}; // {AppID1: [role1, role2], AppID2: [role3, role4]}
if (roles[0].d && roles[0].d.results) {
var r = roles[0].d.results;
for (var i = 0; i < r.length; i++) {
if (!rolesMap[r[i].ApplicationID]) {
rolesMap[r[i].ApplicationID] = [];
}
rolesMap[r[i].ApplicationID].push(r[i]);
}
}
if (apps[0].d && apps[0].d.results) {
var a = apps[0].d.results;
for (var i = 0; i < a.length; i++) {
var app = {
ApplicationID: a[i].Id,
ApplicationName: a[i].ApplicationName,
ApplicationDescription: a[i].ApplicationDescription,
roles: rolesMap[a[i].Id]
};
model.applications.push(app);
model.applicationMap[app.ApplicationID] = app;
}
}
else if(apps[1].d && apps[0].d.results) {
var a = apps[0].d.results;
for (var i = 0; i < a.length; i++) {
var app = {
ApplicationID: a[i].Id,
ApplicationName: a[i].ApplicationName,
ApplicationDescription: a[i].ApplicationDescription,
roles: rolesMap[a[i].Id]
};
model.applications.push(app);
model.applicationMap[app.ApplicationID] = app;
}
}
});
ASPX:
<td class="ms-vb">
Application:
<select data-bind="value: $data.selectedApp, options: $parent.applications, optionsText: 'ApplicationName', optionsCaption: 'Choose an Application'" style="width: 32px" name="Application list" id="dataBox">
</select>
<img src="../SiteAssets/helpbutton.png" class="helpbutton" onmouseover="displayAppHelpText(this);"/>
Role: <select data-bind="value: selectedRole, options: roles, optionsText: 'RoleNameValue', optionsCaption: 'Choose a Role'"></select>
<button data-bind="click: addSelectedRole" id="add_button">Add</button>
<img src="../SiteAssets/helpbutton.png" class="helpbutton" onmouseover="displayRoleHelpText(this);"/>
<span class="hidden">
<select class="appnames" data-bind="value: $data.selectedApp, options: $parent.applications, optionsText: 'ApplicationName', optionsCaption: 'App'"></select>
<select class="appdescriptions" data-bind="value: $data.selectedApp, options: $parent.applications, optionsText: 'ApplicationDescription', optionsCaption: ''"></select>
<select class="rolenames" data-bind="value: selectedRole, options: roles, optionsText: 'RoleNameValue', optionsCaption: 'Please select an Application first'"></select>
<select class="roledescriptions" data-bind="value: selectedRole, options: roles, optionsText: 'Description', optionsCaption: ''"></select>
</span>
So when I click an application I want to change the roll, however I am having problems with this. Thanks
For handling select change you could use one of 2 ways:
Subscribe to observable which $data.selectedApp should be. [this way is more 'Knockout-ish']
Or use knockout event binding.
var viewModel = {
choices: [
{label:"one", code: 1},
{label:"two", code: 2},
{label:"three", code: 3}
],
selectedChoice: ko.observable(2) ,
selectionChanged: function(event) {
alert("The event binding way. New value is " + $( "#eventBindingWay option:selected" ).val());
}
};
viewModel.selectedChoice.subscribe(function(newValue) {
alert("The observable subscribtion way. New value is " + newValue);
});
ko.applyBindings(viewModel);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
Subscribtion way: <select id="subscribtionWay" data-bind="options: choices, value: selectedChoice, optionsText:'label', optionsValue:'code',"></select>
<br /><br />
Event binding way: <select id="eventBindingWay" data-bind="event:{ change:
selectionChanged }">
<option value="A">A label</option>
<option value="B">B label</option>
<option value="C">C label</option>
</select>