Sort HTML emlements by child contents - html

I have these elements in a list. I want to sort the list alphabetically but how do i do that if the text that i want to sort it by is in a child element?
<div class="entry">
<button class="title btn btn-primary">Tale of Memories</button>
</div>

Without seeing your code, it is difficult to know exactly how things will work. Here is a generic solution:
Select all the elements in the list (eg: using querySelectorAll).
Transform the result of step 1 into an array (eg: with this solution from andrewmu)
Use the native sort() method to sort the array (providing your own function to compare values based on whatever you want).
Rewrite the content of the list with the content of the array.
Here is a demo. In it, we sort the list not based on the text directly in each item, but on the text from the span within each of them (for that reason the FA item goes first instead of last). In your case, you will want to change the compare function to get whichever element you want the items to be compared by:
// step 1: select the list items
var items = document.querySelectorAll("#mylist li");
// step 2: convert the node list into an array
var itemsarray = Array.prototype.slice.call(items, 0)
// step 3: sort the array using your own compare function
itemsarray.sort(function(a,b) {
return a.querySelector("span").innerHTML > b.querySelector("span").innerHTML;
});
// step 4: empty the list, and insert the sorted items
var ml = document.getElementById("mylist");
ml.innerHTML = "";
for (var x = 0; x < itemsarray.length; x++) {
ml.appendChild(itemsarray[x]);
}
<ul id="mylist">
<li><span>E</span></li>
<li><span>D</span></li>
<li><span>B</span></li>
<li>F<span>A</span></li>
<li><span>C</span></li>
</ul>

Related

React: How to provide procedurally generated <li> elements distinct HTML id values?

I'm rendering a map of items retrieved from a database and filtered via the value state of an input field and attempting to then set the state of the input field as the value stored in some list item on click. I figured that using document.getElementById().innerHTML would allow me to retrieve the content stored within the appropriate tag and then set it to state which does work, the issue I'm facing is that it will only retrieve the innerHTML of the first item rendered in the map.
I've tried solutions ranging from applying UUID to making the mapped content available to the window and transfering the state of the individual objects but each disparate solution only moves the value of the first item to state - any ideas?
Rendered Content:
window.filteredItems = this.state.items.filter(
(item) => {
return item.companyNameObj.toLowerCase().indexOf(this.state.search.toLowerCase()) !== -1;
}
);
<div className="fixed-width">
<div className="search-container">
<form>
<input type="text" name="search" className="search-bar" placeholder="Search: " onChange={this.handleChange} value={this.state.search} />
</form>
<ul className="search-results">
{window.filteredItems.map((item) => {
return (
<div className="distinct-result-container">
<li key={item.id}>
<div className="image-container">
<img src={item.imageObj} alt={item.companyNameObj + " logo."}/>
</div>
<div className="company-container">
<span onClick={this.stateTransfer}><h3 id={"ID"}>{item.companyNameObj}</h3></span>
<p>Owned by: {item.ownerNameObj}</p>
</div>
</li>
</div>
)
})}
</ul>
</div>
<Footer />
</div>
);
stateTransfer()
stateTransfer(id) {
var search = this.state.search;
var uniqueID = document.getElementById("ID").innerHTML;
this.setState({
search: uniqueID
});
}
The current content of stateTransfer() doesn't represent any significant attempts at approaching a solution to this issue, it's just the minimum required implementation to move the innerHTML content to the input fields value.
EDIT: I've further clarified on the task at hand and a potential solution in the comments below (which follow this), I'm just hoping someone is able to help me with the actual implementation.
#DILEEPTHOMAS The list is comprised of data pulled from a Firebase Realtime Database and is rendered via mapping the filteredList and a search query; that functoionality works fine - what I need is to be able to click the element of any distinct li and have the innerHTML (the text stored in that li's item.companyNameObj) be moved to the value of the input field (so users can navigate the search content with re-typing).
#JoshuaLink I can't necessarily configure the items of the list any
further as it's just data pulled from an external database - I believe
the appropriate solution is to somehow provide a unique HTML ID value
to each newly rendered li and have that selected ID moved to
stateTransfer() where it can be set as the input fields value, I'm
just struggling with the actual implementation of this.
EDIT 2: I've managed to figure out a solution to both parts of the problem as described above - I'll post it as an answer below.
I managed to solve both parts of my problem:
The key issue, which was moving the text stored in each distinct li to the input value, which was apparently easily solved by making my stateTransfer() function accept an event and passing the .innerText value of the h3 through the event (I assumed I would have to use .innerHTML, which would require me to provide each distinct li with a unique generated ID) as follows:
stateTransfer(e) {
var search = this.state.search;
var innerText = e.target.innerText
this.setState({
search: innerText
})
}
The secondary issue, (which I incorrectly assumed was integral to implementing a solution to my question), assigning unique HTML id values to my procedurally generated li's was solved by implementing a for-loop in a componentDidUpdate() function which iterates through the current total length of the list and and assigns an id with the loop iterator concatenated to the end of the string as follows:
componentDidUpdate() {
var i;
var searchCompanyNames = document.querySelectorAll('.comapnyNames');
for(i = 0; i < searchCompanyNames.length; i++) {
searchCompanyNames[i].id = 'companyName-' + i;
}
}
Whilst I didn't need to assign unique ID's to the li's in the correct implementation, it's a useful trick worth noting nonetheless.

Flash AS3 How to display a random item from an xml list then remove that item from the list so it will not be reused

I'm using Flash AS3 trying to display random questions from an xml list on stage. When the user clicks an option it should move on to another question but the one they got should be removed from the list so it will not come back.
I have the randomize part okay but can't figure out how to remove the question from the list.
Here is the section I have.
function randomizeQuestion():void {
var numOfQuestions:Number = xmlData.item.length();
var shuffledNumbers:Array = new Array(randomAns.length);
var randomPos:Number = 0;
//Randomizes selected question
currentQuestion = int(Math.random() * numOfQuestions);
//Randomizes answer numbers
for (var i:int = 0; i < shuffledNumbers.length; i++)
{
randomPos = int(Math.random() * randomAns.length);
shuffledNumbers[i] = randomAns.splice(randomPos, 1)[0];
}
randomAns = shuffledNumbers;
correctAns = xmlData.item[currentQuestion].children().(hasOwnProperty("#correct"));
}
Try to get index:
correctAnsIndex = xmlData.item[currentQuestion].children().(hasOwnProperty("#correct")).childIndex();
or if more elements, to get first one:
correctAnsIndex = xmlData.item[currentQuestion].children().(hasOwnProperty("#correct"))[0].childIndex();
then use delete where appropriate, like here:
delete xmlData.item[correctAnsIndex];
I would add another array to your code in which you can store all the questions that are eligible. As a question gets asked, remove it from that array. So you'll have one array of allQuestions and another array of eligibleQuestions. allQuestions can just be a comprehensive list. Then, push all the questions you want to go through into the eligibleQuestions array. As the questions get answered, splice them from the array.
It would be good to also share an example of your XML file that you're loading, but let's use the example below.
<data>
<item>
<question></question>
<option1></option1>
<option2></option2>
</item>
<item>
<question></question>
<option1></option1>
<option2></option2>
</item>
</data>
Based on the code you have, I assume your function is being called each time you want to randomize a question.
Now what you'd want to do is create an array that holds the number of <item> tags you have outside of this function so that you can remove values from it whenever you want.
You can create this var numOfQuestions:Array = new Array(); as a global variable and then initialize it using a loop before you enter the randomizeQuestions() function.
for(var i = 0; i < xmlData['item'].length(); i++)
{
numOfQuestions.push(i);
}
Basically this array will serve as a method of calling a specific item and removing it from the program without altering the actual XML file in any way.
Then whenever you wish to remove an element you use
numOfQuestions.splice(numOfQuestions.indexOf(valueToBeRemoved), 1);
This will search the array for the element you wish to remove and then remove it from the array.
Lastly the randomizeQuestion function has to be modified.
currentQuestion = int(Math.random() * numOfQuestions.length); //since numOfQuestions is now an array instead of a Number

Item renderer for dynamic DataGrid

I have a problem with dynamic item renderer for data grids elements.
I'm initialiizng columns in my data grid dynamically, like this:
for each (var item in _collection)
{
var i:MyClass= item as MyClass;
var dgc:DataGridColumn = new DataGridColumn(i.Id.toString());
dgc.headerText = i.Name;
cols.push(dgc);
}
_myDataGrid.columns = cols;
To every cell I want to pass integer. When it has -1 value, cell should display specific text but when it's 0 or 1 it should contain checkbox.
Do you know how can I achieve that? I don't any ideas for now, despite I was thinking about this for quite long time. Can you help me with this?
Create itemRenderer with two states. One state with checkbox another with text

getting a random element from an array of movieclips(or labels in a timeline) in Flash CC . Actionscript 3

I am making a pretty neat quiz-game in flashCC right now and I definitely need your help.
My skills are more on the design then the programming side. So to many of you this might seem a baby question (and asked many times before) but from all the answers I saw so far, I couldn't get any results for my project.
So here is the thing :
I need the EXACT script for creating an array (with movieclips inside? or instance names of mcs? How does this even work?)
and a method, to pick a random element of this array without repeats until the "game is over".
Paul
The easiest way to pick a random element from an array without repeating is to first sort the array with a "random" function, then pop or shift items out of it until the array is empty.
Let's say you have an array of items which can be filled with either instances or instance names, you've chosen instance names: :
var FirstArray:Array = ["blau", "orange", "green"];
Now, you'll need a random sort function:
// you do not need to modify this function in any way.
// the Array.sort method accepts a function that takes in 2 objects and returns an int
// this function has been written to comply with that
function randomSort(a:Object, b:Object):int
{
return Math.random() > .5 ? -1 : 1;
}
The way a sort function normally works is it compares two objects and returns -1 if the first item precedes the second item, 1 if the opposite is true, and 0 if they are the same.
So what we're doing in the function above is returning -1 or 1 randomly. This should get the array all jumbled up when you call:
FirstArray.sort(randomSort);
Now that the array is randomly sorted, you can begin pulling items from it like so:
if(FirstArray.length) // make sure there's at least one item in there
{
// since you are using instance names, you'll need to use that to grab a reference to the actual instance:
var currentQuizItem:MovieClip = this[FirstArray.pop()];
// if you had filled your array with the actual instances instead, you would just be assigning FirstArray.pop() to currentQuizItem
// every time you call pop on an array, you're removing the last item
// this will ensure that you won't repeat any items
// do what you need to do with your MovieClip here
}
else
{
// if there aren't any items left, the game is over
}
When strung together, the above code should be enough to get you up and running.
You could try something like:
var array:Array = [1, 2, 3, 4, 5];
var shuffledArray:Array = [];
while (array.length > 0)
{
shuffledArray.push(array.splice(Math.round(Math.random() * (array.length - 1)), 1)[0]);
}
trace('shuffledArray: ', shuffledArray, '\nrandom item: ', shuffledArray[0]);

How do i populate an Array in one class based on a textfield in another class?(Actionscript 3.0)

i have a class (TheList.as). in which i have an array "Data" and it has a couple of values. Then i have a loop through which i am creating a scrollable list which uses the values from "Data" array. [I am trying make a unit converter]
Then i have another class "Units.as". In that class i have created three instances of "TheList". A main list ("myList"), and to sublists "ListFrom" and "ListTo". They are using values from "Data" array. Now i have text field whose value changes to whatever item is clicked. When i click "Angle" in the main list, i want the sublists to get populated with ("Degree", "Radian" etc)..
Here is what i tried
if(myList._TextLabel.text == "Angle")
{
ListFrom.Data = ["Degree", "Radian"];
}
But nothing happens, i do not get any error either. When i do this in an "ENTER_FRAME" event and trace (ListFrom.Data), i can see that the values change, but they do not get assigned to the list items in the list. I would really appreciate the help. Thanks!
Here are complete Classes for understanding the situation better(the code is pretty messy, as i am a newbie to OOP)
TheList.as: http://pastebin.com/FLy5QV9i
Units.as : http://pastebin.com/z2CcHZzC
where you call ListFrom.Data = ["Degree","Radian"], make sure when the data changed, the renders in the ListFrom have been set new data. for example, you may use MyRender in ListFrom for show, you should debug in the set data method in MyRender.
you should call the code below after you call ListFrom.Data = ["Degree","Radian"];
for (var i:int = 0; i < Data.legnth;i++) {
var render:MyRender = ListFrom[i] as MyRender;
if (render) {
render.data = Data[i];
} else {
var render:MyRender = new MyRender();
render.data = Data[i];
ListFrom.addChild(render);
}
}
You can use event listeners, singleton classes or reference one class to another, depending on the style you want. All are equally valid and fast / efficient.