How to add dropdown menus dynamically based on previous selection? - javascript

Assume that I have a hierarchy of categories/subcategories such as:
Books
Fiction
Cooking
Seafood
Pizza
IT
HTML
JavaScript
ReactJS
NodeJS
As you have noticed, we have an unknown depth of categories where ReactJS have a depth of 3, but Fiction have a depth of 1
I am trying to create a form that includes a dropdown menu of root categories (Books, Clothes, Candies, ...etc). Whenever the user clicks on a root category (assume it is Books). Another dropdown will appear with the subcategories (Fiction, Cooking and IT). After that, when the user clicks on IT, another dropdown menu will appear below which will be HTML and JavaScript. Finally, when the user clicks on JavaScript, the final dropdown menu will appear which will contain ReactJS and NodeJS.
Please note that:
The user can choose any level and procceed. I mean he can choose Books and submit the form, or click NodeJS and submit the form.
I want to give the user the ability to rollback. I mean that maybe the user clicks on Books > IT > HTML > JavaScript > NodeJS. He can go to the second dropdown menu (Fiction, Cooking and IT), and then choose Cooking. In this case, all the drop menus below the second dropdown menu will be deleted and we will have a new drop menu which contains Seafood and Pizza.
When we submit the form, only the final dropdown menu value will be sent to the server.
I am not that strong in Frontend, I have already built and tested the Backend which receives the category/subcategory id and then returns all of the subcategories underneath it.
My questions are:
Is my approach good? (You can suggest better approaches)
If my approach is good, how to implement it in Vanilla JavaScript?
Here is a minimal code:
<div id="myDiv">
<select name="category">
<option value="">Please select a category...</option>
<!-- Some for-loop that is getting the main categories successfully -->
</select>
</div>
<script>
const request = new Request(
'Here is the URL to the controller that already gives me the subcategories successfully', {
method: 'POST',
body: JSON.stringify({parent: 1}), // 1 is the id of the parent category that we want to get its subcategories
}
);
fetch(request).then(function (response) {
return response.json();
}).then(function (json) {
for (const i in json) {
console.log(json[i]['name']); // This line prints the subcategories names successfully
}
});
</script>
It is not necessarily to give me the full code, I only need some guidelines.

Related

Cypress unable to select multiselect with loop

I am writing a React application that I'm testing with Cypress. In my integration tests I've written a cypress command that takes an array of strings, in order to select items in a multi-value select box.
The code I'm using looks roughly like this:
Cypress.Commands.add("command", (options) => {
options.forEach((option) => {
cy.get("div[data-g-portal-id='1']") // this is the container for the select box dropdown
.find("div[role='menubar']")
.contains(option)
.click({ force: true });
});
}
I've tried various iterations of this, including things like cy.wrap and .each. Whatever I do, when the array contains more than one item, it clicks one item, the item is marked as selected successfully, then it clicks the other item, marks it as selected, but the first item loses its selection state. Its as if the internal state of the component never really got the initial change.
I've confirmed this is not a bug in my application; when testing it manually, the multi-select works fine. But Cypress just doesn't want to know. Any help would be much appreciated.
The v2.grommet.io/select uses a "portal" to display the dropdown options.
The portal is just a div that's appended to body when the dropdown opened and removed again when an option is clicked.
Problem is, there isn't a property to connect the dropdown and portal containing the options. There may be other portals present e.g the Layer component uses a portal.
The options portal we need to target will always be the last portal on the page (since we just opened the dropdown). In the custom command, applying the .last() command will select the options portal.
Cypress.Commands.add("multiselect", (options) => {
options.forEach((option) => {
cy.get(`[data-g-portal-id]`)
.last() // just opened the dropdown so option are in the last portal
.find("div[role='menubar']")
.contains(option)
.click();
});
});
cy.get('input[name="my-select"]')
.click(); // open dropdown
.multiselect(['First', 'Third']);
cy.get('input[name="my-select"]')
.click(); // close dropdown
cy.get('input[name="my-select"]')
.should('have.value', 'multiple')
The test ends with dropdown displaying the text "multiple".
Configuration of the Select,
<Select
multiple // allow multiple selected options
closeOnChange={false} // do not close the dropdown between selections
name="my-select"
options={myOptions}
...
/>

Get each row selected data in angular

I have 3 days of data, say from Monday to Wednesday
There are 3 columns of data(date, subject are text boxes, level is a drop down)
User ID: 100
Date Subject Level(each will be a dropdown,
this level data come from another table)
1/1/2015 English Beginner (Beginner, Intermediate, Advanced)
1/2/2015 Mathematics Beginner
1/3/2015 Physics Intermediate
If someone comes in for first time, i want to load the levels data from the other table.
If user chooses, say 'Beginner' for 1/1/2015, i need to save that to the table, when the same user selects again 1/1/2015, i need to load the Beginner and not along with rest of the levels.
In the stored table:
User ID Date Subject Level (columns)
100 1/1/2015 English Beginner
Levels table
Level (column)
Beginner
Intermediate
Advanced
This is how i am displaying the data for above condition:
Based on a boolean flag, that is set in client side code - IsDataSavedInDb
Loading the saved level from database, if the data is already saved.
<select name="myLevel" ng-show="IsDataSavedInDb" ng-model="myReponse.Level">
<option value="{{myReponse.AssignedTo}}" selected="selected">
{{myReponse.Level}}
</option>
</select>
Loading all levels from database,if the data was never saved, so that user can make a selection:
<select id="myLevels" name="myLevels" ng-show="IsDataSavedInDb==false"
ng-model="myReponse.Level">
<option value="select">-Select-</option>
<option ng-repeat="level in Levels" value="{{level.Level}}" >
{{level.Level}}
</option>
</select>
Question - Suppose, if the user comes in first time, selects each row a different level and clicks save button? How to i get each row's selected level name and save it?
Please suggest.

Select field populated with multiple entries after one checkbox change

I have something in my mind, but I have no idea how to get it done, so I hope I can get some advise here.
I'm working on an activity registration app (using Laravel), where every activity will be registered. Very important is that we need to record who was invited and who actually attended. I already have this part running. My issue is more on the practical side.
I use jQuery Select2 for the multiple select fields for invitees and attendees. Imagine now that there's a group of users that need to be invited or attend virtually all activities, while the invitation or attendance of others depends on the type of activity. Using Select2, I can only select users one at a time and that sucks if you need to do that for, say, 50 users for virtually every activity.
What is the best way to have a "group" that can be selected, which selection fills in all the names of those in the group in the select field? Or is there a better way to get this done?
I'm seeing something in my head, where there are checkboxes next to the select field, representing the groups. When you tick a checkbox of a group, the select field is populated with all users who are part of that group.
I have no idea ow this can be done. I looked around and every search brings up select boxes populating select boxes. None handle checkboxes.
Any advise on how to get this done?
My PHP/MySql is intermediate, Javascript/Ajax is very basic.
One strategy would be to build a control (checkbox element) that will set or toggle the selection of your group of users whenever it's clicked. Say we have the following markup:
<select class="my-big-group-select" multiple="multiple">
<!-- assorted options here -->
</select>
<label>
<input type="checkbox" class="toggle-default-group" />
Use my default big group of users
</label>
The Select2 API allows you programmatic control over the component it generates.
You can read more about it here: https://select2.github.io/examples.html#programmatic
Here's one way to leverage this knowledge using jQuery with Select2:
<script>
var groupSelect = $('.my-big-group-select').select2();
var groupToggle = $('.toggle-default-group');
var myBigGroup = ["Aaron", "Beth", "Cindy"]; // assorted option values
groupToggle.on("click", function() {
if ($(this).is(':checked')) {
groupSelect.val(myBigGroup).trigger('change');
} else {
var currentlySelected = groupSelect.val();
if (currentlySelected) {
var filteredSelections = currentlySelected.filter(function(key) {
return myBigGroup.indexOf(key) < 0;
});
groupSelect.val(filteredSelections).trigger('change');
}
}
});
</script>
Here's a CodePen that shows it all in action: http://codepen.io/anon/pen/qNQKOd
Of course you can build on this to make additional enhancements (the ability to select multiple groups, for example).
As an alternative, you may consider other code libraries like Bootstrap Multiselect: https://davidstutz.github.io/bootstrap-multiselect/
Hope this points you in the right direction!

Delete or hide some values in drop down list which is populating by stored procedure using JavaScript?

I'm working on Classic ASP and JavaScript.
I have two dropdown lists: Dropdownlist1 and Dropdownlist2. In first dropdown list it shows list of companies, in second dropdown list it shows departments.
When the user select the company A from 1st dropdown list so, it should show all of departments.
When the user selects the company B from 1st dropdown list, it should hide couple of departments in the 2nd dropdown list.
The dropdowns are populated from stored procedures.
How can I do this?
There's two ways to go with:
You can either use AJAX to make a Request to get the options for your second dropdown by passing the selection of the first one (that's what most people would do). That would look something like this in your JS (not tested!)
(Edit: forgot to mention that the example below uses jQuery)
$('select#company').on('change', function () {
$.ajax('/some-asp-file.asp', {
type: 'POST',
data: {
'Company': $('select#company').val()
},
success: $.proxy(function(data){
$('select#department').html(data);
}, this)
});
});
and something like this in /some-asp-file.asp (also not tested!)
<%
dim Company
dim Department, Departments
Company = trim(request.form("Company"))
if Company <> "" then
Departments = ' // -> Result Array from your SP here where you pass in "Company"
for each Department in Departments
%>
<option value="<%=Department%>"><%=Department%></option>
<%
next
else
%>
<option value="-1">-</option>
<%
end if
%>
OR (the decision also depends on the amount of data you have) you could initially get ALL the data and store it in a JS object and replace it client-sided. This is probably more frustrating to code with all the double quote escaping in ASP etc, but I could write you a quick example if you insist.

Auto Refresh Select Menu's in Web Apps

Is it possible to refresh the Select Menu's without hitting the controller and regenerating the whole Select Menu in the Controller and sending back to the respective Div ?
I can sent the data in JSON format from the Controller but I don't want to sent the entire Div all over ... .. because it breaks the DRY principle . This is a very common scenario , I am wondering if its possible to make the Select Menu listen to some object in the JS , so that , if that Object is modified , refresh the Select Menu accordingly .... The object can be made like {value,text} etc ...Does any one have any pointers ?
How the select gets generated in the Web App ?
<form>
<content>
<div id=unique id>
<for each in some model>
<option> <value>
</div>
<content>
We have many such forms with Select Menu's ... Everytime we tend to write select to another file and call it again .
<div id=unique id>
<for each in some model>
<option> <value>
</div>
Why not re-use ?
1) Because we only need to refresh the Select not the Content
2) The data obtained in the main page is from some dictionary (pre-populated from DB) , in the refresh , we might obtain the data from the DB direct ...
So sticking to dry principle can I just populate SELECT contents by some UI listeners to some Object ? If the Object changes , refresh the select with new value . I will just write AJAX to get the JSON of the new SELECT MENU .
What about:
$.each(jsonData, function(index){
$('select').append('<option value="'+jsonData[index].value+'">'+jsonData[index].text+'</option>');
});
When JSON Data looks like:
[
{
"value":1,
"text":"Text for First Item"
},
{
"value":2,
"text":"Text for 2nd Item"
}
]
Hope I understand your question ;-)

Categories

Resources