I am trying to use a List within dart to Store information - flutter

How can I retrieve this information as when I am testing it using print it is returning the following error?
I have searched online to try and find a solution but alas for the past 30 minutes i have not been able to find one. If there is an easier and more efficient way of storing information then please let me know.
Apologies as I am still learning dart, moving from JS.
List<Object> chosenSelection = [
[
'Advanced Higher', //[0][0]
false /**Enabled? */, //[0][1]
[
'Style',
'MelodyHarmony',
'RhythmTempo',
'TextureStructureForm',
'Timbre',
] /**Categories */, //[0][2][0-4]
],//[0]
[
'Higher', //[0][0]
false /**Enabled? */, //[0][1]
[
'Style',
'MelodyHarmony',
'RhythmTempo',
'TextureStructureForm',
'Timbre',
] /**Categories */, //[0][2][0-4]
]
];
print(chosenSelection[0][0]); //Output: 'Advanced Higher'
print (chosenSelection[0][2][4]); // Output 'Timbre'
Resulting error:
type '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of type 'List' of 'function result'
I am trying to access the data 'Advanced Higher' and then 'Timbre' within the variable.

I'm not sure what's the question here, but this code doesn't compile for 2 reasons:
You're missing a closed bracket in the second print;
You're trying to access the elements of an Object as if it is a nested List.

You are trying to implement a 2d and 3d list. But you have declared a 1d list.
In order to declare a 2d list you need to declare it as List<List<Object>> and for a 3d list: List<List<List<Object>>>
So you need to declare List<List<List<Object>>> chosenSelection, and then
print(chosenSelection[0][0]); //Output: 'Advanced Higher'
print (chosenSelection[0][2][4]); // Output 'Timbre'

I ended up settling for making the information part of a class.
class ChosenLevel {
String level;
bool overallToggled = false;
Map categories = {
'Style': true,
'MelodyHarmony': false,
'RhythmTempo': false,
'TextureStructureForm': false,
'Timbre': false,
};
Color _color;
ChosenLevel(this.level, this._color);
get categoriesNumber {
return categories.length;
}
specificCategory(index) {
switch (index) {
case 0:
return 'Style';
case 1:
return 'MelodyHarmony';
case 2:
return 'RhythmTempo';
case 3:
return 'TextureStructureForm';
case 4:
return 'Timbre';
/* default:
throw ("Something strange happend"); */
}
}
toggleCat(c) {
this.categories['${c}'] = !this.categories['${c}'];
}
toggleLevel() {
this.overallToggled = !this.overallToggled;
}
#override
String toString() {
return '{${level}, ${categories}}';
}
}

Related

How to change a list to lower case? Keep getting error in for loop

This is the code I have for an exercise on exercism. I want to change the colours typed to lower case just to be sure there won't be any errors. But the way I have now gives me an error on the for loop "the typed string used in the for loop must implement iterable dart". Help?
void main(){
ResistorColorDuo obj = new ResistorColorDuo();
obj.result(['Orange','Black']); //I want something that would make these colours lower case so there's no error if someone types it with upper case
}
class ResistorColorDuo {
static const COLOR_CODES = [
'black', 'brown', 'red', 'orange', 'yellow', 'green', 'blue', 'violet', 'grey', 'white',];
void result(List<String> givenColors) {
String numbers = '';
for (var color in givenColors.toString().toLowerCase()) {//But this throws an error "the type string used in the for loop must implement iterable dart"
numbers = numbers + COLOR_CODES.indexOf(color).toString();
}
if (givenColors.length != 2)
print ('ERROR: You should provide exactly 2 colors');
else
print (int.parse(numbers));
}
}
Here is the answer.
Your mistake was here givenColors.toString().toLowerCase() the givenColors() is a list and list can't be converted to string as you are giving in a for loop. In the below code we take a single value from the list and then convert to the lower case.
This line color.toLowerCase() converts the value to the lower case as color contains a single value from the list on each iteration.
Updated Code
void main(){
ResistorColorDuo obj = new ResistorColorDuo();
obj.result(['Orange','Black']); //I want something that would make these colours lower case so there's no error if someone types it with upper case
}
class ResistorColorDuo {
static const COLOR_CODES = [
'black', 'brown', 'red', 'orange', 'yellow', 'green', 'blue', 'violet', 'grey', 'white',];
void result(List<String> givenColors) {
String numbers = '';
for (var color in givenColors) {//But this throws an error "the type string used in the for loop must implement iterable dart"
numbers = numbers + COLOR_CODES.indexOf(color.toLowerCase()).toString();
}
if (givenColors.length != 2)
print ('ERROR: You should provide exactly 2 colors');
else
print (int.parse(numbers));
}
}
givenColors.toString() converts your list to String; so it can't be iterated;
There are few solutions you can take;
List colorsLowercase = [];
for (var color in givenColors) {
colorsLowercase.add(color.toLowerCase())
...
}
Or like #pskink suggested
givenColors.map((c) => c.toLowerCase())

Dart: warning "info: This function has a return type of 'int', but doesn't end with a return statement")

I got a warning on the following piece of code, and I don't know why.
List<Map<String, int>> callNoInfo = [];
int getCallNo(String phoneNo) {
callNoInfo.forEach((item) {
if (item.containsKey(phoneNo)) {
return item[phoneNo];
}
});
return 0;
}
The warning is:
This function has a return type of 'int', but doesn't end with a return statement. (missing_return at [project_name] lib\helper\call_no.dart:35)
Can anyone tell me why this happens? thanks in advance
In the forEach method, you are creating a lambda function without explicitly defining the return type, so Dart is attempting to infer it from the return statements. If we pull the function out of the forEach method, it might help to see what I mean:
...
(item) {
if (item.containsKey(phoneNo)) {
return item[phoneNo];
}
}
...
The function includes a return statement that returns item[phoneNo], which is an int value. Using this, Dart infers that the return type of this lambda function is int. However, now that it knows this, it also notices that if the code execution does not enter the if block, there is no return statement to match the else side of the if condition. If the item object does not contain the key phoneNo, what is the method going to return?
(The answer is that the method will implicitly return null which is why the message is only a warning and not a compiler error, but the warning appears because this probably wasn't intentional by you the developer and also as a nudge to help you make your code less reliant on invisible Dart runtime magicks.)
To fix this, there needs to be another return outside of the if block:
...
(item) {
if (item.containsKey(phoneNo)) {
return item[phoneNo];
}
return 0;
}
...
However, now there's a different problem. The forEach method on lists has the following signature:
forEach(void f(E element)) → void
In fact, there are two problems. First, the method passed as the parameter needs to have a return type of void, and the forEach method itself also has a return type of void. This means that you cannot return values from within the forEach method at all.
The thing about the forEach method is that it is intended to iterate over the collection and process each of the values within it. It's not meant to (and can't) search for a value and return it once it's found. Furthermore, the iteration is exhaustive, meaning once you start it, the method cannot be stopped until each and every element in the collection has been iterated over.
Which is why, as the other answers have pointed out, what you really should be doing is using a for or for in loop:
List<Map<String, int>> callNoInfo = [];
int getCallNo(String phoneNo) {
for(var item in callNoInfo) {
if (item.containsKey(phoneNo)) {
return item[phoneNo];
}
}
return 0;
}
(I'm not sure why you don't get a compiler error for assigning a lambda function with a return value of int to the forEach method which clearly is requesting a one with a void return type. But if I had to guess, I'd say the Dart runtime treats them as compatible and reconciles the difference in return type by simply discarding the return value of the lambda function.)
You don't have an else case for the if statement inside the forEach loop. Even though you might have one at the end, it still is expecting a case everywhere.
List<Map<String, int>> callNoInfo = [];
int getCallNo(String phoneNo) {
callNoInfo.forEach((item) {
if (item.containsKey(phoneNo)) {
return item[phoneNo];
}
// you don't have a case for here since it's in a callback
});
return 0;
}
However, you could do this which uses a for in loop:
List<Map<String, int>> callNoInfo = [];
int getCallNo(String phoneNo) {
for (var item in callNoInfo) {
if (item.containsKey(phoneNo)) {
return item[phoneNo];
}
}
return 0;
}

How to print fields with numeric names in mongo shell? [duplicate]

I'm trying to access a property of an object using a dynamic name. Is this possible?
const something = { bar: "Foobar!" };
const foo = 'bar';
something.foo; // The idea is to access something.bar, getting "Foobar!"
There are two ways to access properties of an object:
Dot notation: something.bar
Bracket notation: something['bar']
The value between the brackets can be any expression. Therefore, if the property name is stored in a variable, you have to use bracket notation:
var something = {
bar: 'foo'
};
var foo = 'bar';
// both x = something[foo] and something[foo] = x work as expected
console.log(something[foo]);
console.log(something.bar)
This is my solution:
function resolve(path, obj) {
return path.split('.').reduce(function(prev, curr) {
return prev ? prev[curr] : null
}, obj || self)
}
Usage examples:
resolve("document.body.style.width")
// or
resolve("style.width", document.body)
// or even use array indexes
// (someObject has been defined in the question)
resolve("part.0.size", someObject)
// returns null when intermediate properties are not defined:
resolve('properties.that.do.not.exist', {hello:'world'})
In javascript we can access with:
dot notation - foo.bar
square brackets - foo[someVar] or foo["string"]
But only second case allows to access properties dynamically:
var foo = { pName1 : 1, pName2 : [1, {foo : bar }, 3] , ...}
var name = "pName"
var num = 1;
foo[name + num]; // 1
// --
var a = 2;
var b = 1;
var c = "foo";
foo[name + a][b][c]; // bar
Following is an ES6 example of how you can access the property of an object using a property name that has been dynamically generated by concatenating two strings.
var suffix = " name";
var person = {
["first" + suffix]: "Nicholas",
["last" + suffix]: "Zakas"
};
console.log(person["first name"]); // "Nicholas"
console.log(person["last name"]); // "Zakas"
This is called computed property names
You can achieve this in quite a few different ways.
let foo = {
bar: 'Hello World'
};
foo.bar;
foo['bar'];
The bracket notation is specially powerful as it let's you access a property based on a variable:
let foo = {
bar: 'Hello World'
};
let prop = 'bar';
foo[prop];
This can be extended to looping over every property of an object. This can be seem redundant due to newer JavaScript constructs such as for ... of ..., but helps illustrate a use case:
let foo = {
bar: 'Hello World',
baz: 'How are you doing?',
last: 'Quite alright'
};
for (let prop in foo.getOwnPropertyNames()) {
console.log(foo[prop]);
}
Both dot and bracket notation also work as expected for nested objects:
let foo = {
bar: {
baz: 'Hello World'
}
};
foo.bar.baz;
foo['bar']['baz'];
foo.bar['baz'];
foo['bar'].baz;
Object destructuring
We could also consider object destructuring as a means to access a property in an object, but as follows:
let foo = {
bar: 'Hello World',
baz: 'How are you doing?',
last: 'Quite alright'
};
let prop = 'last';
let { bar, baz, [prop]: customName } = foo;
// bar = 'Hello World'
// baz = 'How are you doing?'
// customName = 'Quite alright'
You can do it like this using Lodash get
_.get(object, 'a[0].b.c');
UPDATED
Accessing root properties in an object is easily achieved with obj[variable], but getting nested complicates things. Not to write already written code I suggest to use lodash.get.
Example
// Accessing root property
var rootProp = 'rootPropert';
_.get(object, rootProp, defaultValue);
// Accessing nested property
var listOfNestedProperties = [var1, var2];
_.get(object, listOfNestedProperties);
Lodash get can be used in different ways, the documentation lodash.get
To access a property dynamically, simply use square brackets [] as follows:
const something = { bar: "Foobar!" };
const userInput = 'bar';
console.log(something[userInput])
The problem
There's a major gotchya in that solution! (I'm surprised other answers have not brought this up yet). Often you only want to access properties that you've put onto that object yourself, you don't want to grab inherited properties.
Here's an illustration of this issue. Here we have an innocent-looking program, but it has a subtle bug - can you spot it?
const agesOfUsers = { sam: 16, sally: 22 }
const username = prompt('Enter a username:')
if (agesOfUsers[username] !== undefined) {
console.log(`${username} is ${agesOfUsers[username]} years old`)
} else {
console.log(`${username} is not found`)
}
When prompted for a username, if you supply "toString" as a username, it'll give you the following message: "toString is function toString() { [native code] } years old". The issue is that agesOfUsers is an object, and as such, automatically inherits certain properties like .toString() from the base Object class. You can look here for a full list of properties that all objects inherit.
Solutions
Use a Map data structure instead. The stored contents of a map don't suffer from prototype issues, so they provide a clean solution to this problem.
const agesOfUsers = new Map()
agesOfUsers.set('sam', 16)
agesOfUsers.set('sally', 2)
console.log(agesOfUsers.get('sam')) // 16
Use an object with a null prototype, instead of the default prototype. You can use Object.create(null) to create such an object. This sort of object does not suffer from these prototype issues, because you've explicitly created it in a way that it does not inherit anything.
const agesOfUsers = Object.create(null)
agesOfUsers.sam = 16
agesOfUsers.sally = 22;
console.log(agesOfUsers['sam']) // 16
console.log(agesOfUsers['toString']) // undefined - toString was not inherited
You can use Object.hasOwn(yourObj, attrName) to first check if the dynamic key you wish to access is directly on the object and not inherited (learn more here). This is a relatively newer feature, so check the compatibility tables before dropping it into your code. Before Object.hasOwn(yourObj, attrName) came around, you would achieve this same effect via Object.prototype.hasOwnProperty.call(yourObj, attrName). Sometimes, you might see code using yourObj.hasOwnProperty(attrName) too, which sometimes works but it has some pitfalls that you can read about here.
// Try entering the property name "toString",
// you'll see it gets handled correctly.
const user = { name: 'sam', age: 16 }
const propName = prompt('Enter a property name:')
if (Object.hasOwn(user, propName)) {
console.log(`${propName} = ${user[propName]}`)
} else {
console.log(`${propName} is not found`)
}
If you know the key you're trying to use will never be the name of an inherited property (e.g. maybe they're numbers, or they all have the same prefix, etc), you can choose to use the original solution.
I came across a case where I thought I wanted to pass the "address" of an object property as data to another function and populate the object (with AJAX), do lookup from address array, and display in that other function. I couldn't use dot notation without doing string acrobatics so I thought an array might be nice to pass instead. I ended-up doing something different anyway, but seemed related to this post.
Here's a sample of a language file object like the one I wanted data from:
const locs = {
"audioPlayer": {
"controls": {
"start": "start",
"stop": "stop"
},
"heading": "Use controls to start and stop audio."
}
}
I wanted to be able to pass an array such as: ["audioPlayer", "controls", "stop"] to access the language text, "stop" in this case.
I created this little function that looks-up the "least specific" (first) address parameter, and reassigns the returned object to itself. Then it is ready to look-up the next-most-specific address parameter if one exists.
function getText(selectionArray, obj) {
selectionArray.forEach(key => {
obj = obj[key];
});
return obj;
}
usage:
/* returns 'stop' */
console.log(getText(["audioPlayer", "controls", "stop"], locs));
/* returns 'use controls to start and stop audio.' */
console.log(getText(["audioPlayer", "heading"], locs));
ES5 // Check Deeply Nested Variables
This simple piece of code can check for deeply nested variable / value existence without having to check each variable along the way...
var getValue = function( s, context ){
return Function.call( context || null, 'return ' + s )();
}
Ex. - a deeply nested array of objects:
a = [
{
b : [
{
a : 1,
b : [
{
c : 1,
d : 2 // we want to check for this
}
]
}
]
}
]
Instead of :
if(a && a[0] && a[0].b && a[0].b[0] && a[0].b[0].b && a[0].b[0].b[0] && a[0].b[0].b[0].d && a[0].b[0].b[0].d == 2 ) // true
We can now :
if( getValue('a[0].b[0].b[0].d') == 2 ) // true
Cheers!
Others have already mentioned 'dot' and 'square' syntaxes so I want to cover accessing functions and sending parameters in a similar fashion.
Code jsfiddle
var obj = {method:function(p1,p2,p3){console.log("method:",arguments)}}
var str = "method('p1', 'p2', 'p3');"
var match = str.match(/^\s*(\S+)\((.*)\);\s*$/);
var func = match[1]
var parameters = match[2].split(',');
for(var i = 0; i < parameters.length; ++i) {
// clean up param begninning
parameters[i] = parameters[i].replace(/^\s*['"]?/,'');
// clean up param end
parameters[i] = parameters[i].replace(/['"]?\s*$/,'');
}
obj[func](parameters); // sends parameters as array
obj[func].apply(this, parameters); // sends parameters as individual values
I asked a question that kinda duplicated on this topic a while back, and after excessive research, and seeing a lot of information missing that should be here, I feel I have something valuable to add to this older post.
Firstly I want to address that there are several ways to obtain the value of a property and store it in a dynamic Variable. The first most popular, and easiest way IMHO would be:
let properyValue = element.style['enter-a-property'];
however I rarely go this route because it doesn't work on property values assigned via style-sheets. To give you an example, I'll demonstrate with a bit of pseudo code.
let elem = document.getElementById('someDiv');
let cssProp = elem.style['width'];
Using the code example above; if the width property of the div element that was stored in the 'elem' variable was styled in a CSS style-sheet, and not styled inside of its HTML tag, you are without a doubt going to get a return value of undefined stored inside of the cssProp variable. The undefined value occurs because in-order to get the correct value, the code written inside a CSS Style-Sheet needs to be computed in-order to get the value, therefore; you must use a method that will compute the value of the property who's value lies within the style-sheet.
Henceforth the getComputedStyle() method!
function getCssProp(){
let ele = document.getElementById("test");
let cssProp = window.getComputedStyle(ele,null).getPropertyValue("width");
}
W3Schools getComputedValue Doc This gives a good example, and lets you play with it, however, this link Mozilla CSS getComputedValue doc talks about the getComputedValue function in detail, and should be read by any aspiring developer who isn't totally clear on this subject.
As a side note, the getComputedValue method only gets, it does not set. This, obviously is a major downside, however there is a method that gets from CSS style-sheets, as well as sets values, though it is not standard Javascript.
The JQuery method...
$(selector).css(property,value)
...does get, and does set. It is what I use, the only downside is you got to know JQuery, but this is honestly one of the very many good reasons that every Javascript Developer should learn JQuery, it just makes life easy, and offers methods, like this one, which is not available with standard Javascript.
Hope this helps someone!!!
For anyone looking to set the value of a nested variable, here is how to do it:
const _ = require('lodash'); //import lodash module
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c);
// => 4
Documentation: https://lodash.com/docs/4.17.15#set
Also, documentation if you want to get a value: https://lodash.com/docs/4.17.15#get
You can do dynamically access the property of an object using the bracket notation. This would look like this obj[yourKey] however JavaScript objects are really not designed to dynamically updated or read. They are intended to be defined on initialisation.
In case you want to dynamically assign and access key value pairs you should use a map instead.
const yourKey = 'yourKey';
// initialise it with the value
const map1 = new Map([
['yourKey', 'yourValue']
]);
// initialise empty then dynamically assign
const map2 = new Map();
map2.set(yourKey, 'yourValue');
console.log(map1.get(yourKey));
console.log(map2.get(yourKey));
demo object example
let obj = {
name: {
first_name: "Bugs",
last_name: "Founder",
role: "Programmer"
}
}
dotted string key for getting the value of
let key = "name.first_name"
Function
const getValueByDottedKeys = (obj, strKey)=>{
let keys = strKey.split(".")
let value = obj[keys[0]];
for(let i=1;i<keys.length;i++){
value = value[keys[i]]
}
return value
}
Calling getValueByDottedKeys function
value = getValueByDottedKeys(obj, key)
console.log(value)
output
Bugs
const getValueByDottedKeys = (obj, strKey)=>{
let keys = strKey.split(".")
let value = obj[keys[0]];
for(let i=1;i<keys.length;i++){
value = value[keys[i]]
}
return value
}
let obj = {
name: {
first_name: "Bugs",
last_name: "Founder",
role: "Programmer"
}
}
let key = "name.first_name"
value = getValueByDottedKeys(obj, key)
console.log(value)
I bumped into the same problem, but the lodash module is limited when handling nested properties. I wrote a more general solution following the idea of a recursive descendent parser. This solution is available in the following Gist:
Recursive descent object dereferencing
Finding Object by reference without, strings,
Note make sure the object you pass in is cloned , i use cloneDeep from lodash for that
if object looks like
const obj = {data: ['an Object',{person: {name: {first:'nick', last:'gray'} }]
path looks like
const objectPath = ['data',1,'person',name','last']
then call below method and it will return the sub object by path given
const child = findObjectByPath(obj, objectPath)
alert( child) // alerts "last"
const findObjectByPath = (objectIn: any, path: any[]) => {
let obj = objectIn
for (let i = 0; i <= path.length - 1; i++) {
const item = path[i]
// keep going up to the next parent
obj = obj[item] // this is by reference
}
return obj
}
You can use getter in Javascript
getter Docs
Check inside the Object whether the property in question exists,
If it does not exist, take it from the window
const something = {
get: (n) => this.n || something.n || window[n]
};
You should use JSON.parse, take a look at https://www.w3schools.com/js/js_json_parse.asp
const obj = JSON.parse('{ "name":"John", "age":30, "city":"New York"}')
console.log(obj.name)
console.log(obj.age)

AG Grid: Better way for validation row - valueSetter?

Is there a better way to validate a row in ag-grid than with valueSetter?
I can achieve the validation with that but I am not sure, if there is a better way.
https://www.ag-grid.com/javascript-grid-value-setters/#properties-for-setters-and-parsers
I want to validate two fields in the row. DateFrom and DateUntil (they are not allow to be null and DateFrom must be lower than DateUntil).
There are two ways of possible validation handling:
First: via ValueSetter function
and
Second: via custom cellEditor component
I suggest that it would be better to split the logic between custom components, but as you said you need to validate two cell-values between themselves.
On this case from UI perspective you could try to combine them inside one cell and it would be easily to work with values via one component only.
You could override the valueSetter and call the grid api transaction update instead.
Here is pseudo-code that shows how you could implement this.
valueSetter: params => {
validate(params.newValue, onSuccess, onFail);
return false;
};
validate = (newvalue, success, fail) => {
if (isValid(newValue)) {
success();
} else {
fail();
}
};
onSuccess = () => {
// do transaction update to update the cell with the new value
};
onFail = () => {
// update some meta data property that highlights the cell signalling that the value has failed to validate
};
This way you can also do asynchronous validation.
Here is a real example of an async value setter that has success, failure, and while validating handlers that do transaction updates when validation is done.
const asyncValidator = (
newValue,
validateFn,
onWhileValidating,
onSuccess,
_onFail
) => {
onWhileValidating();
setTimeout(function() {
if (validateFn(newValue)) {
onSuccess();
} else {
_onFail();
}
}, 1000);
};
const _onWhileValidating = params => () => {
let data = params.data;
let field = params.colDef.field;
data[field] = {
...data[field],
isValidating: true
};
params.api.applyTransaction({ update: [data] });
};
const _onSuccess = params => () => {
let data = params.data;
let field = params.colDef.field;
data[field] = {
...data[field],
isValidating: false,
lastValidation: true,
value: params.newValue
};
params.api.applyTransaction({ update: [data] });
};
const _onFail = params => () => {
let data = params.data;
let field = params.colDef.field;
data[field] = {
...data[field],
isValidating: false,
lastValidation: params.newValue
};
params.api.applyTransaction({ update: [data] });
};
const asyncValidateValueSetter = validateFn => params => {
asyncValidator(
params.newValue,
validateFn,
_onWhileValidating(params),
_onSuccess(params),
_onFail(params)
);
return false;
};
Here is a code runner example showing this in action: https://stackblitz.com/edit/async-validation-ag-grid-final
Have a look at this two snippets, these come from our internal knowledge base (accessible to customers)
When editing a value in column 'A (Required)', you will see that it does not allow you to leave it empty. If you leave it empty and return the edit, it will be cancelled.
//Force Cell to require a value when finished editing
https://plnkr.co/edit/GFgb4v7P8YCW1PxJwGTx?p=preview
In this example, we are using a Custom Cell Editor that will also validate the values against a 6 character length rule. While editing, if the value is modified outside of 6 characters, it will appear in red, and when you stop editing the row, the value would be reset, so it only accepts a complete edit if the value is valid.
//Inline Validation while editing a cell
https://plnkr.co/edit/dAAU8yLMnR8dm4vNEa9T?p=preview

jquery select2 plugin how to match only beginning of word

I am using select2 in my website and i want the autocomplete to match only the beginning of the word. For example, if I type "CA" I want CAmeroun to appear and not "vatiCAn".
I figured out how to resolve this by searching in the documentation (here https://github.com/select2/select2/issues/428).
In select2 library, replace in select2.js :
matcher: function(term, text) {
return stripDiacritics(''+text).toUpperCase().indexOf(stripDiacritics(''+term).toUpperCase()) >= 0;
},
by :
matcher: function(term, text) {
if (text.toUpperCase().indexOf(term.toUpperCase()) == 0) {
return true;
}
},
And tadaaa. It works. I hope someone who is better in JS (99% of JS developers) could give a better answer or create a good patch.
Don't forget to minify your JS ;) !
Inspired by #IsmailH answer. I've merged this code as matchCustom in the provided example, here.
And here's my modification,
function matchCustom(params, data) {
// If there are no search terms, return all of the data
if ($.trim(params.term) === '') {
return data;
}
// `params.term` should be the term that is used for searching
// `data.text` is the text that is displayed for the data object
if (data.text.toUpperCase().indexOf(params.term.toUpperCase()) == 0) {
var modifiedData = $.extend({}, data, true);
// You can return modified objects from here
// This includes matching the `children` how you want in nested data sets
return modifiedData;
}
// Return `null` if the term should not be displayed
return null;
};