Nested dropdown in react-select - javascript

I am using react-select to render the dropdown. The options to render the dropdown looks like this
[
{
text:'Fruit',
value:'mango'
level: 0
},
{
text:'Seasonal',
slug: 'saasonal',
level: 1
},
{
text:'Orange',
slug: 'orange',
level: 2
},
{
text:'Mango',
slug: 'mango',
level: 2
},
{
text: 'Winter',
slug:'winter',
level:1
},
{
text: 'Plum',
slug:'plum',
level:2
}
]
I would like the dropdown to be like
Fruit
Seasonal
Orange
Mango
Winter
Plum
I have tried adding a group to the react-select, but then the group heading is not clickable.
I have also referred to the stackoverflow link
[https://stackoverflow.com/questions/53119912/how-can-i-create-nested-option-groups-in-react-select-v2][1]
and tried creating a recursive dropdown in the same manner it is posted on the link above by passing my options as the data but was not successful.
The order of the within nested dropdown is based on the level.

react-select actually just got this feature builtin in July.
Here's the pull request where they implemented it.
Here's a working example from the pull request page.
I'm not sure if it has made its way into the master branch yet or not but you can always pull from the version listed in the package.json file in the sample above if the sample code doesn't work with the version you're using.
EDIT: Scratch that, you want group headings to be clickable. I don't think that was part of this commit.

Related

Dynamically add options to select2 with a POST request

I am trying to add options dynamically to a multiselect form using Select2. Backend is Ruby on Rails and I have defined a create method for the "genre" model (it's a movie db) in question that takes input as json and adds to the database.
The code below works, but only somewhat :)
when I want to add a new genre "abc" - first of all, the select2 drop-down shows "no results" (and doesn't give the option to add the genre).
However in the BACKEND - the entry is actually created and available for future manipulations. In addition - there isn't just one genre "abc" added, but actually one "a", another one "ab", and a third one "abc".
So two things I need to fix - and I don't know enough JS to know how... :/ ...
how do I ensure that only ONE genre - "abc" is created?
how do I make sure that the genre is shown during creation, and selected properly when I update the form?
Code:
$("#genre-select").select2({
tags: true,
tokenSeparators: [","],
createTag: function (params) {
let term = $.trim(params.term);
$.post("/genres.json", { genre: { name: term } });
},
});

Handling updates on nested screens using Context and React Navigation in React Native

Let's say I am building a shopping list app. I have the ability to create different shopping lists. I have three screens:
-- Shopping Lists: displays all the lists
---- List Details: displays all the items from a list
------ List Item Details: displays all the info about an item
To store the state and avoid prop drilling I use Context. My state could look like:
shoppingLists = [
{
title: 'Groceries',
items: [{
name: 'Apples',
quantity: 3
... (other info)
},
items: [{
name: 'Oranges',
quantity: 6,
...
}]
},
{
title: 'Office Supplies',
items: [{
name: 'Paper',
quantity: 2
... (other info)
},
items: [{
name: 'Pens',
quantity: 25,
...
}]
}]
When I tap on a Shopping List on the Shopping Lists screen I do
navigation.navigate('ListDetails', {params: listItem})
In the List Details screen I have de ability to change the quantity of an item or delete them. If I do any of this actions I have to make an API call to my server to update the value on the database. Here are my questions:
Currently I store the values in a local variable in my screen for example:
const [title, setTitle] = useState(props.route.params.title)
const [items, setItems] = useState(prop.route.params.items)
And if I make a change in the quantity I use setState to update my local array and then make an API call to update the context. This results problematic when adding more nested screens.
For example if I would give the user the ability to change the item quantity in the List Item Details screen, when the user goes back to the List Details screen, the values would not be updated.
My question is, which is the correct way to grab the state of the context and update it locally?
For example should I do something like:
navigation.navigate('ListDetails', {params: { listName: 'Groceries' })
And then in my List Details screen grab the correct list from the array like:
const {lists} = useContext(ShoppingLists)
const list = lists.filter(l => l.title === props.route.params.title)
What is the correct way?
The other question I have is a more general question. I want to use optimistic responses: when the user updates the quantity of an item in the list I update it locally and send the request to the server. If there's an error rollback the change. Which would be the correct way of doing this?
Thanks!
I would advise against updating context data in such a way. You could create a setList() method in the context instead, or updateList() to aggregate new data to the existing data.
This is related to the previous one. You could wrap the logic of POSTing to the server in a try-catch block and throw an error when it's not successful. Then you can set the new value only when it's successful. Another option would be to return the promise, so you could handle errors from outside, like setList().then(response => {}).catch(error => {}) though I don't think this looks that good.
Think you're over complicating it and also in your list you're not showing an id for each item. You should build your database with all the items and their unique id then call upon that when needed. The id should never change and that's easier to pass around and reference.
For example you can build an object in context with just the id and quantity and use useReducer for this:
https://reactjs.org/docs/hooks-reference.html#usereducer

Implement filter options in Gatsby

I'm fairly new to Gatsby and React and I couldn't find an answer to my problem.
I want to be able to have filtering options on the home of my website that allow the user to display only content relevant to that filter.
Let's say my posts are recipes and they are categorized by type: main, snack and dessert.
I want a filter, can be a button or a drop-down it doesn't matter, and when the user selects it I will display only the items relevant. Ideally I'm going to have multiple filters, around 4-5 for different properties of the frontmatter of my posts .
From what I understand it's not really something I can do with graphql because after build I cannot access it anymore so I was seeking some advice from more experienced devs.
If you have a small set of posts, I think you can make a search component that get all the posts & then use something like js-search or flexsearch to index them.
In a non-page component (not in src/pages folder), you can use StaticQuery to get all the posts' info.
Say you have this graphql query result:
data: {
allMarkdownRemark: {
edges: [{
node: {
id: '1234-1233...',
fields: {
slug: '/hello/'
},
frontmatter: {
title: 'hello',
tags: [ 'go', 'js' ]
}
}
}, {
node: {
id: ...
}
}]
}
}
Then you can index & search for post, say, with js-search:
const posts = data.allMarkdownRemark.edges.map(({ node }) => node) // unwrap edges
const postIndex = new JsSearch.Search('id')
postIndex.addIndex(['frontmatter', 'tags']) // index node.frontmatter.tags
postIndex.addIndex(['frontmatter', 'title'])
postIndex.addDocuments(posts) // add data to array
const results = postIndex.search('go')
console.log(results) // [{ id: '1234-1233...', frontmatter: { title: 'hello', tags: [ 'go', 'js' ]}}]
Then you can store this result in, say, the component's state & render the results as posts.
Gatsby's doc also has a guide on adding search to your site, though I think the js-search part is a bit overwhelming.

Working with bootstrap modal and ember

I have a working version of bootstrap modals who open the nested list ('options') of a json who looks like that :
{
product: [{
id: 1,
title: 'Some dope shoes',
options: [
{ id: 1, name: 'Color' },
{ id: 2, name: 'Size' }
]
},
{
id: 2,
title: 'Some dope',
options: [
{ id: 3, name: 'Lenght' },
{ id: 4, name: 'Flavor' }
]
}
]
}
I've wrote everything for modals with templates I did used any file component. The trick is to make uniq modal id. Url looks like :
<a href="#" data-toggle="modal" data-target="#ma-modal{{optionid}}" title={{title}}>{{mmmh}}</a>
And modals looks like :
<div class="modal" id="ma-modal{{optionid}}"></div>
I don't feel confident about this code and because I'm learning ember I would like to know if doing all of this in template without any file components is something bad ?
Playing with the ids appears to me as a hack.
In my opinition, creating a component for modal is a way better solution, because:
Ember will generate ids and you will have an access to rendered element inside lifecycle hooks, so in many cases there is no need to know an id.
You will likely need to call some js-function to show a modal. Component gives a possibility to do this in the right moment (after rendering all elements) by using lifecycle hooks
It is easy to re-use a component if needed.
You may found all necessary info about components in documentation. Additionally, you can read about new (introduced in 1.13) lyfecycle hooks in this blog post.
And of course, you can use one of a many ember-cli addons, if you will find an appropriate one

LumX lx-select not updating ng-model

I started using the LumX framework recently, and I was trying to use their Selects directive here, but I'm not clear on their documentation. This is what I've got so far:
<lx-select ng-model="selectedPriority" placeholder="Priority" choices="priorities">
<lx-select-selected>
{{ $selected.name }}
</lx-select-selected>
<lx-select-choices>
{{ $choice.name }}
</lx-select-choices>
</lx-select>
And this is how I'm defining priorities (within the controller for the div containing the lx-select)
$scope.priorities = [
{ name: 'Urgent', id: 1 },
{ name: 'Very important', id: 2 },
{ name: 'Not important', id: 3 },
{ name: 'None', id: 4 }
];
Which does give me a list to select from, but the selectedPriority model never gets updated, so that whenever I try to use that value, it's always undefined. I can't even run the example they provide in the documentation page, but I'm not sure what I'm missing.
So initializing the selectedPriority variable this way:
$scope.selects = {
selectedPriority: undefined,
};
seemed to do the trick. I tried without declaring selectedPriority inside an array but as far as I could tell, this is the only way the model gets properly updated.
Check your angular version and see if it matches your lumX version's minimum requirements.
For example a match of version 0.3.24 of lumX and version 1.2.28 of angular would produce exactly the issue you have encountered (model wouldn't update), as far as I have experimented.

Categories