I'm creating a site for my JavaScripting class and one of the first issues that has arisen has been the entry of data into arrays, and doing it in an efficient and quick pattern and then allowing the user to select entries and then use their selections in a function that updates either on refresh, or automatically.
My first task is to create multiple arrays that are linked and contain data for all the tanks offered in the game. That's more than 100 tanks.
My thought is to create a 'tank' object that then has a list of properties; 'armor values', 'nation', 'tank name'.
Assuming that works we move on.
The formatting and syntax is most likely wrong in the following uses.
Then we take each tank object and assign it to an array.
As an example, tank{0} would access values about the m4 Sherman.
I also need a method to display drop down lists of the available data that the user can select. For example;
Nation: American Tank: M4 Sherman Rotation of tank: 30 degrees.
The user's selection of nation should also narrow down the available tanks that can be selected. I'm assuming I would need another function that looks at the 'tank' object array that can then narrow down the results?
What I've Tried
I tried to make a simple list with Html and JavaScript and got this far:
<div id="select_nation">
<select>
<script>select_nation();</script>
</select>
</div>
I can't do that.
What I was trying to test was the ability to create a list using <select> from HTML and then populating that list with a function that would access an array that would return all values in the Nation Array that would then be used with .innerHTML to populate the different selection in the <select> tags.
Thank you for your help ahead of time and the small fence of text in front of you.
This demo will show you how you can build a select list from an array of javascript objects. From there you can look at which option they select and narrow your list of tanks to display elsewhere. This will all be done in javascript
EDIT - showing tanks list based on nation
Updated demo that displays the tanks that are from the selected nation:
http://jsbin.com/segojezosi/1/edit?html,output
Putting tank objects into an array is fine.
You can put your script anywhere and add options to the <select>.
Let's say that your <select> has an id.
<select id="mySelect">
Here is how you add options to that using JS.
var x = document.getElementById("mySelect");
var option = document.createElement("option");
option.text = "Tank";
x.add(option);
Consider using a framework which can do all these for you in a single command.
Angular is my favorite. jQuery is little flat - but would also do the job.
Please follow this and this tutorial before you go any further in this project.
Good luck.
Related
I am looking for a way of adding functionality to a text area input on an HTML page where you can write into a text field and as you type, if you add an ampersand and #start_typing it would provide you with a list of options which will incrementally reduce as you type more of the letters of a word from the list.
I basically want what you can do in Atlassian Confluence when you add a colleague into a page or comment. I want to be able to add one or more value in a text input with the help of a list of options.
I have found autocomplete from a drop list as you type as an alternative to select from a list but that is where the selection is the only thing that ends up in the onscreen variable.
For example, I want to type #gross_value = #net_value + #tax_value and at each point of adding an # in that entire sentence, it would drop a list of options I can either select from or keep typing (using the list as a reference just like you do in Visual Studio Code.)
So here's my code example below. In my use case, I know the name of the list I want to use, it would be schema_values (a list of origin and destination schema values used in mapping) and I know that I would use one of those values more than once in a formula.
In the context of the example below, I might want to type the sentence, 'my favourite car is a #Saab and I don't really like #Skoda' - what I would expect to happen is as I type the # I get the full list of cars then when I type S I only get the options for SaaB and Skoda and when I've selected or finished typing the item which exists in the list, it leaves the ampersand there.
I have a program which transforms from one data schema to another and the interface requires me to create formulas which include the selection of values to set the from and to parameters which match the schema values which I will put together in a set of options as shown.
It would be used for a mathematical calculation or to map from one value to another. The purpose of the interface is to create a configuration file which can be processed by an application.
<input type="text" list="cars" />
<datalist id="cars">
<option>Volvo</option>
<option>Saab</option>
<option>Skoda</option>
<option>Mercedes</option>
<option>Audi</option>
</datalist>
I have a table with variable number of records (could be up to hundreds) where its body is build with one ng-repeat.
Within each record, there are two input fields of type select where their contents is also built using ng-repear and the number of options for each is about 100.
This is working right now, except that it takes a lot of time for the page to be built (several seconds; I guess due to the large number of html records that AngularJS is adding to the DOM).
Here is an example of one of the selects:
<select class="form-control" ng-model="One_Source.Measuring_Method_Code">
<option ng-selected="{{One_Method.Value == One_Source.Measuring_Method_Code}}"
ng-repeat="One_Method in All_Collections.Parameters_Test_Methods"
value="{{One_Method.Value}}"
title="{{One_Method.Test_Method_Name}} | {{One_Method.Method_Internal_Name}}">
{{One_Method.Value}}
</option>
</select>
Two questions:
Is there a simple way to speed up the page building process?
As shown in the example, each option in the list has a title clause displaying a detailed description of the option's meaning. How can I add a title to the select showing the description of the current value?
For the first question I was thinking about building the list of options for each select element only upon clicking on it, but I'm not sure if that would be the best way to do it.
Try using one time bindings so that Angular doesn't watch the value by prefixing it with ::. It can also be more efficient to use track by in your ng-repeat if each row has a unique value, like an ID.
<option
ng-selected="{{One_Method.Value == One_Source.Measuring_Method_Code}}"
ng-repeat="One_Method in All_Collections.Parameters_Test_Methods track by One_Method.id"
value="{{::One_Method.Value}}"
title="{{::One_Method.Test_Method_Name}} | {{::One_Method.Method_Internal_Name}}"
>
{{::One_Method.Value}}
</option>
If you still can't gain the performance you're expecting from #doublesharps's answer, you will have to implement one of the following:
You could build a custom list that has a 'load more' button which would destroy say the first '50' options and load the next 50.
A better option would be to turn this into an autocomplete, where the user searches for values.
Virtual repeat - Something angular material does really well, it constantly draw's and re-draws new elements based on the scroll position inside the element.
Other resources:
http://blog.scalyr.com/2013/10/angularjs-1200ms-to-35ms/
https://github.com/stackfull/angular-virtual-scroll
http://klajd.github.io/angular-virtual-repeat/#/Home
I found a PARTIAL SOLUTION that still needs to be polished but is quite promising.
During creation of the page, I do not make use of ng-repeat for the options but instead deploy a single option with the value received for the field from the database (if any, otherwise the select element is left blank).
When the user clicks on the select element a $scope function is invoked that checks the number of options within the select element and, if less or equal to 1, the inner HTML of this select element is re-generated and deployed.
Though clicking on all these select in the page will take (accumulative) a comparable time as when built upon load, this time is distributed over several events (the user clicking on all the select elements) and hence it is not perceived by the user.
Now, by polishing I mean that there is a strange behavior. In order to see the generated list of options, I need to click on the select twice. Will keep investigating this and post the solution (hoping I find one).
Having troubles getting values from dynamically added dropdown in thymeleaf.
This is my first
<select th:field="${offer.offerItemList[__${iterationStatus.index}__].mapa}" class="form-control input-sm ofa">
<option value="0" >---Choose option---</option>
<option th:each="attribute : ${offer.offerProductAttribute}" th:value="${attribute.id}" th:text="${attribute.name}"></option>
</select>
Based on selecton from this dropdown i am generating another dropdown with code similar to this :
var options = '<select th:field="offer.list" class="form-control input-sm"> <option th:value="0">--Choose--</option>';
$.each(value.offerProductAttributeValuesList, function (index, value) {
options += '<option th:value="' + value.id + '">' + value.value+ '</option>';
});
options+= '</select>';
of.closest('tr').find('td:last').html(options);
Dom elements generate fine. Everything is ok but values are never submitted with the rest of input fields.
I have done this many times but with previously rendered
<select>
dropdown on the server side, and i would just appendTo() options, but in this case i cannot do that since i potentially have more than 20 dropdowns, based on clients selection from previous dropdown.
I hope i am being clear enough about my issue.
I am gonna answer my own question, since it took me quite some time to get around this problem, and my solution will probably help someone in the future.
The problem was : i had list of objects, and each one of those objects had another list of objects.
The problem is much easier to solve if you just render entire view from the backend (i was using thymeleaf). That way you can use thymeleaf expressions to map everything correctly
Like this :
First you gonna need for each to iterate over top level list
<tr th:each="item,iterationStatus : ${offer.offerItemList}">
You need to use iterationStatus to iterate over nested List, like this :
<select th:field="${offer.offerItemList[__${iterationStatus.index}__].mapa}">
This little piece of code __${iterationStatus.index}__ will basically use iteration index and you will end up with number for each iteration and rendered view will look like this offer.offerItemList[0].mapa, and 1 and 2 and so on.
this way values will be mapped correctly, BUT, if you want to add fields dynamically things get a bit more complicated.
There is jquery issue. Since jquery pretty much binds selectors when page is rendering, even if you write add another element, say <div class="temp">
and write perfectly good jquery function something like this $('.temp').on('click',function(){ console.log("clicked")});
nothing will happen since jquery didnt bind your newly created element to any select/event listener. The solution is to use (document).
$(document).on("click",".temp",function(){console.log('clicked');})
ok we have fixed front end issue, now newly created items work, but how do i tell spring to bind them to each object within list, which is part of another list? well you will have to use iteration index again :
When rendering the view you will need to save iteration index value in each element(using hidden fields)
Get value for each input field to jquery var like this : var iteration = $(this).closest('tbody').find('td:first-child').find('input').attr('value'); ofc this is path to where i have placed hidden input field, you will have to tell jquery where to look according to your structure.
You will simulate array and index numbers like this
var options = '<select name="offerItemList['+iteration+'].mapaValues">';
And the very last thing you need to be careful about is this : Say you have Object which you would normally send from controller like this model.addAttribute("offer",offer); object Offer has attribute, list of Products, so you would access that list with simple offer.productsList, but each product has list of AttributeValues. So final setup looks like this
offer.products[0].attributes[0].name products is an arrayList of objects of class Product, attributes is an arrayList of objects of class AttributeValues and name is a String. In order to let spring create object of class AttributeValues with information spring is receiving from dynamically(and non-dinamically) created forms from the frond-end, you will need to teach him how. If your new form with has input type="text" you are sending back String, so you will need to create a Custom constructor for
your class AttributeValues which will receive a String and which will tell Spring how to "construct" instance of that class with String.
finally create two constructors, one default and one with String as a value :
public AttributeValues(){}; and another for String public AttributeValues(String n){this.name = n;};
The problem you're most likely seeing here is that you're generating thymeleaf markup on the client-side.
Thymeleaf is a server-side templating language, so the browser (and hence the Javascript) will only ever see plain HTML coming back.
Here's a few approaches to consider:
submit the form each time to get new data in, which means no javascript is required
Output every possible dropdown into your HTML, and show/hide them as needed when the user selects options. Some fairly simple Javascript required, but as you mention - the page size may be pretty big
Add a JSON endpoint to your Spring webapp (see the spring #ResponseBody annotation) that will return just the data you need, then pull that JSON data in when the user selects a dropdown using something like jQuery.get()
I have tried a very simple example with Sortable.js: Two lists: One is currently empty, and will store item copies from the other list (which is static).
I tried defining pull and put values for each list, defining the same group name, but it does not work. In fact the static elements from the filled list are not draggable at all.
I have written the example at JSbin. Since I am new to JS, I accept all kind of constructive comments.
BTW: any way of drawing the bootstrap list borders even when empty?
I have edited the jsbin and did the following corrections
Replaced the sortable.js with
<script src="//cdn.jsdelivr.net/sortable/latest/Sortable.min.js"></script>
You were accessing the ids with _ (instances_list, main_list) whereas the ids were having an -
For the appending to work I had to add one item by default to instances-list than keeping it empty
JSBin
Honestly been looking everywhere..
The traditional 3-dropdown list dynamically populated from database:
1st table gives airport departure
2nd table gives airports choices
from 1st choice
3rd table show routes between 1 and 2.
That works perfectly!!
When passenger chooses a route from the 3rd drop list I want to check if the value from 3rd dropdownlist is represented in a 4th table called "donations"
Some routes are marked for donation possibility where passengers can donate their unused baggagecapacity to charity
My last hurdle is:
when 3rd list is selected --> check for donationpossibilities--> if possible then show a hidden div on submit
...
I've tried and read so much and gotten a lot more clever and I think I have the query to check the values in order, but I'm lost...
Not sure what programming language you are using to load the dropdowns from your database, but one option that you could try is that when you are adding the html option elements to the 3rd dropdown list you could add a data attribute to each, for example:
<option value="route 1" data-can-donate="true">...</option>
Then if you are using jquery you could bind the change event to the 3rd dropdown and do something like this:
$('#ddlRoutes').change(function() {
var canDonate = $('#ddlRoutes > option:selected').data('can-donate');
if (canDonate) {
$('#myDiv').show();
}
};
Obviously this is untested but it may work for what you are trying to do.