Is there a way to sort a table based on a cell value in Angular? - html

My current table looks like this:
Status
Draft
Pending
Complete
I want to sort them based on the value of the cells. Is there a way to do that? I've only been able to sort them using this code:
onChange(status: string){
const sortState: Sort = {active: status, direction: 'desc'};
this.sort.active = sortState.active;
this.sort.direction = sortState.direction;
this.sort.sortChange.emit(sortState);
}
But I want to sort using the values of the status themselves since I'd want to create a button which when click sorts starting from complete or draft or pending.

I'm a little confused by your question, but I think I understand what you're asking.
You're going to want to convert your values into an array and then use the .sort() function. So, assuming you have an array of your cells, we can call that let array = Cell[], you can then access the status of the cells like this:
sortCells(){
let array = Cell[]; // here we're assuming there is already a cell type and a cell.active parameter, like shown in your example.
let possibleValues = ["Draft","Pending","Complete"]; // easier way to compare two values
array.sort((a,b)=>{
let aIndex = possibleValues.indexOf(a.active); // index of gets the location of the element in an array
let bIndex = possibleValues.indexOf(b.active);
if(a > b){
return -1;
} else if(b > a){
return 1;
}else{
return 0; // they are equal
}
})
}
You can read more about sort here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

Related

Node-red - need a multi-input function for a number value

So I'm just getting to grips with node-red and I need to create a conditional global function.
I have two separate global.payloads set to a number value of either 0 or 1.
What I need to happen now is, if global.payload is equal to value 1 then follow this flow, if it is equal to value 0 then follow this one.
I'm just a little confused with the syntax for the function statement. Any help gratefully appreciated.
Since you haven't accepted the current answer, thought I'd give this a try.
I think this is what you need to handle inputs from two separate global contexts. I'm simulating them here with two separate inject nodes to demonstrate:
The checkconf inject node emits a 1 or a 0. Same for the meshstatus node. Substitute your real inputs for those inject nodes. The real work is done inside the function:
var c = context.get('c') || 0; // initialize variables
var m = context.get('m') || 0;
if (msg.topic == "checkconf") // update context based on topic of input
{
c = {payload: msg.payload};
context.set("c", c); // save last value in local context
}
if (msg.topic == 'meshstatus') // same here
{
m = {payload: msg.payload};
context.set('m', m); // save last value in local context
}
// now do the test to see if both inputs are triggered...
if (m.payload == 1) // check last value of meshstatus first
{
if (c.payload == 1) // now check last value of checkconf
return {topic:'value', payload: "YES"};
}
else
return {topic:'value', payload: "NO"};
Be sure to set the "topic" property of whatever you use as inputs so the if statements can discriminate between the two input. Good luck!
You can use the Switch node to do this, rather than a Function node.

Adding two javascript functions(depending on input)

I have put together a calculator what calculates a price, depending on user input. It works fine with one input, but now I have to scale it a little with a second user input. But here's the catch: the user might not want to put anything to the field, so it will be empty. And that's the thing that brakes my code. I could duplicate the calculator function and return the values and add those two together in a third function, but it will not work when there's an empty value.
Just for the sake of it, some trivial HTML code:
//When I only calculate with this user input, its easy
<input type="text" id="rocktext"><br>
// But how to consider this and do the same exact calculations like with the
//first one and add those two result together?
<input type="text" id="rocktext2"><br>
The code in the end should look like:
Take first user input, calculate the price(like in code below)
IF(!!) there is a second user input, calculate the price and add it to
the first one
Am I being a moron to try it with JS or just a moron in the firstplace?
Hope to hear from You, guys!
J.
The initial JS code is as follows:
function priceCalc() {
var inputs = document.getElementById("rocktext").value;
var length = inputs.length;
var accept = 6;
var initPrice = 8;
if (inputs<=accept){
// Since the code is much simpler right now i just put the result in HTML as follows:
document.getElementById("rockpricetotal").innerHTML = initPrice + " dollars";
//I can also return the the value calculated here like so:
//retVal = initPrice;
}
else {
var intLength = parseInt(length, 10);
var lengthGap = intLength - accept;
var totals = lengthGap * 0.8 + initPrice;
var prec = totals.toPrecision(3);
// Since the code is much simpler right now i just put the result in HTML as follows:
document.getElementById("rockpricetotal").innerHTML = prec + " dollars";
// Here also the return clause can be possible with the calculation result like so:
//retVal = prec;
}
// And the final return as an alternative to the innerHTML :
// return retVal;
}
Making it scalable, you can add a class to all the inputs which may be in the function (something like calcInput), so you iterate all of them and if the value isn't empty (and if it's a valid number), you put it in the calculation.
Or you can just verify if the second input is empty, if so, calls functionOne, if not, calls functionTwo:
function twoDifferentWays() {
var valueOne = document.querySelector("#rocktext").value;
var valueTwo = document.querySelector("#rocktext2").value;
if (!!valueTwo && !isNaN(valueTwo)) {
callsFunctionOne(valueOne, valueTwo);
} else {
callsFunctionTwo(valueOne, valueTwo);
}
}

Combining two items (recipe-like)

I'd like a user to be able to combine two items and if compatible will yield a new item. In this example, the item IDs will be saved as Strings.
I was wondering what the most efficient way to do this would be, while making sure that swapped order will always yield the same result, so the user could input the order:
item X + item Y = item Z
item Y + item X = item Z
I've tried using Dictionaries and Objects, but I just haven't been able to get anything to work. I've also tried some various libraries that include HashMap/HashSet but nothing is working. here's some pseduo-code:
itemRecipe1:HashSet = new HashSet();
itemRecipe1.add("2");//Add item with ID of 2
itemRecipe1.add("3");//Add item with ID of 3
inputRecipe:HashSet = new HashSet();
inputRecipe.add("3");//Add item with ID of 3 (swapped)
inputRecipe.add("2");//Add item with ID of 2 (swapped)
recipeList:HashMap = new HashMap();
receipeList.put(itemRecipe1, "11");//Recipe has been added, the result of the recipe should be item 11
//This should output as TRUE since the composition of itemRecipe1 and inputRecipe are the same, despite a different input order.
trace(receipeList.containsKey(inputRecipe));
If anyone has a solution for this issue, please elt me know as I am willing to implement any design I can get working. I just don't see how a Dictionary could work as the key order matters.
So you're trying to associate two or more objects with each other. The first thing you need is some primitive data you can use to represent each item uniquely, typically an ID. This should give you something like the following to begin with:
class Item {
public var _id:int;
public function Item(id:int) {
_id = id;
}
public function get id():int { return _id; }
}
Now you need some piece of data that establishes a relationship between multiple Items using this ID. That could be as simple as the following, with a little extra functionality thrown in to see if an input list of these IDs matches the relationship:
class ItemRelationship {
private var _items:Vector.<Item>;
public function ItemRelationship(items:Vector.<Item>) {
_items = items;
}
public function matches(ids:Vector.<int>):Boolean {
if (_items.length !== ids.length) {
return false;
}
for each (var item:Item in _items) {
var found:Boolean = false;
for each (var id:int in ids) {
if (item.id === id) {
found = true;
break;
}
}
if (!found) return false;
}
return true;
}
public function get items():Vector.<Item> { return _items; }
}
This lets us do something like this, assuming we have a bunch of items (item1, item2, ...) with IDs.
var rel:ItemRelationship = new ItemRelationship(new <Item>[item1, item2]);
And then:
trace(rel.matches(new <int>[1,2])); // true
trace(rel.matches(new <int>[2,1])); // true
trace(rel.matches(new <int>[3,4])); // false
Now all we need is something that stores all of these relationships and lets us fetch one based on a list of input IDs:
class RelationshipCollection {
private var _relationships:Vector.<ItemRelationship>;
public function RelationshipCollection(relationships:Vector.<ItemRelationship>) {
_relationships = relationships;
}
public function find(ids:Vector.<int>):ItemRelationship {
for each(var relationship:ItemRelationship in _relationships) {
if (relationship.matches(ids)) return relationship;
}
return null;
}
}
Put a load of relationships in there:
var collection:RelationshipCollection = new RelationshipCollection(new <ItemRelationship>[
new ItemRelationship(new <Item>[item1, item4]),
new ItemRelationship(new <Item>[item2, item3])
]);
And give it a whirl:
trace(collection.find(new <int>[1, 3])); // null (no match)
trace(collection.find(new <int>[1, 4])); // works
trace(collection.find(new <int>[3, 2])); // works
trace(collection.find(new <int>[2, 3])); // works
Of course for the sake of readability you can rename each class to something more appropriate for its application e.g. Item => Potion, ItemRelationship => Recipe, RelationshipCollection => RecipeBook.
so the user could input the order
The first step is to limit the possible input. If you allow any type of input, you have to parse that input and things get complicated very quickly.
Create an input method that only allows the user to put two items together, say for example via drag and drop of the items to only 2 slots.
I just don't see how a Dictionary could work as the key order matters.
The important part is to design the keys well.
As #George Profenza pointed out in the comments, you could change your IDs to a different format. Instead of having 1, 2, 3, ... n you could use 1, 2, 4, ... 2^n. The advantage is that you can combine any two IDs uniquely via bitwise or operator (|). In the following example, two such IDs are combined (binary notation):
00001
| 10000
--------
10001
As you can see, each ID occupies a separate position in binary: the 1st position and the 5th. Combining both via or operator means that now both 1st and 5th position are 1. The order doesn't matter. If you use such IDs in the form of powers of 2 you can combine them regardless of the order to form pairs, which can then be used as keys to a dictionary.
Another solution is to simply sort the pair of IDs.
The combination 3-2 becomes 2-3 and the combination 2-3 stays 2-3. Both 2-3 and 3-2 lead to the same result.
You can then build your data structure accordingly, that is: the outer data structure is for the lower ID number and the nested, inner one is for the bigger ID number. Here's some pseudo code with generic objects:
var map:Object = {};
map["2"] = {"3":"combination 2-3"};
To access that, you'd do something like:
trace(map[Math.min(ID1, ID2)][Math.max(ID1, ID2)])
There's also the brute force way of doing it by storing both possible combinations in the data structure. The code for that could roughly look like that:
var map:Object = {};
map["2"] = {"3":"combination 2-3"};
map["3"] = {"2":"combination 2-3"};
Now both
trace(map[ID1][ID2]);
and
trace(map[ID2][ID1]);
Should yield the same result.

Difficulty splitting array and returning a value from within it; Javascript

I have got an array that consists of strings. I have made a function that searches the array based on the search term parameter. However, when i run the code it only ever outputs the string at index 0 of the array. I want it to return the corresponding url in the array when a search is run.
Any help would be very much appreciated. Thanks in advance.
So you are trying to return URL based on the String after the ~?
Do the line
arrayOfURL[i].toLowerCase().split('~')[i];
seem weird to you? Imagine as i increases, eg. i = 4
arrayOfURL[4].toLowerCase().split('~')[4];
Does that last [4] make sense?
I am guessing the reason it never got past the first element is because the code actually erroring out on that part.
I think what you want is (likewise for the return line, you'll want [0]
arrayOfURL[i].toLowerCase().split('~')[1];
I would also take a look at
if (z >= searchtoLower)
what are you trying to compare there?
The problem may be in the second i param:
var z = arrayOfURL[i].toLowerCase().split('~')[i];
The string will be splitted into 2 parts (index 0, 1). Why did you select part i?
This is a correct version of your program:
var arrayOfURL = [
"http://www.google.co.uk~Google is a search engine.",
"http://www.yahoo.co.uk~Yahoo is another search engine.",
"http://bing.com~Bing is a decision engine."
];
function findURL(arrayOfURL,search)
{
var searchtoLower = search.toLowerCase();
for (var i = 0; i < arrayOfURL.length; i++)
{
var z = arrayOfURL[i].toLowerCase().split('~')[1];
if (z.indexOf(searchtoLower) != -1)
return arrayOfURL[i];
}
return "Nothing Found!";
}
findURL(arrayOfURL,"decision")
I hope it can help you.
I think you should be doing
var terms = arrayOfURL[i].toLowerCase().split('~');
if(0 <= terms[1].indexOf(searchToLower))
// ^ ^
// | |-- 0 <= indexOf method determines
// | if searchToLower is a substring of terms[1]
// |
// |-- term[1] gets the part after the first "~"
and
return terms[0]; //terms[0] is the part before the first "~"
I would also consider returning null or the empty string "" in case of failure (instead of returning the arbritrary "Nothing Found!" message)

How to find specific value in a large object in node.js?

Actually I've parsed a website using htmlparser and I would like to find a specific value inside the parsed object, for example, a string "$199", and keep tracking that element(by periodic parsing) to see the value is still "$199" or has changed.
And after some painful stupid searching using my eyes, I found the that string is located at somewhere like this:
price = handler.dom[3].children[3].children[3].children[5].children[1].
children[3].children[3].children[5].children[0].children[0].raw;
So I'd like to know whether there are methods which are less painful? Thanks!
A tree based recursive search would probably be easiest to get the node you're interested in.
I've not used htmlparser and the documentation seems a little thin, so this is just an example to get you started and is not tested:
function getElement(el,val) {
if (el.children && el.children.length > 0) {
for (var i = 0, l = el.children.length; i<l; i++) {
var r = getElement(el.children[i],val);
if (r) return r;
}
} else {
if (el.raw == val) {
return el;
}
}
return null;
}
Call getElement(handler.dom[3],'$199') and it'll go through all the children recursively until it finds an element without an children and then compares it's raw value with '$199'. Note this is a straight comparison, you might want to swap this for a regexp or similar?