I want to make a dynamic filter method, but don't know how to include conditions dynamically.
Example
var do_test_1 = true,
do_test_2 = false,
do_test_3 = true;
Now there are three tests:
if (foo == bar) // test 1
if (john == doe) // test 2
if (jane == doe) // test 3
Now I want to build a dynamic if clause, based on the do_test vars.
Real use case
I have a list of tasks and want to filter them:
If the "assigned to me" filter is active, it should return only the the tasks that are assigned to me.
If the "high priority" filter and the "assigned to me" filter is active, it should return only the tasks that are assigned to me and have a high priority.
... and so on ...
I played around with the filter method, but I only get it working with an OR logic (show tasks that are assigned to me or have a high priority):
var $show = $tasks.filter(function(index, task) {
var $task = $(task);
return ((task.data('assigned') && filters['mytasks']) || (task.data('priority') == 3 && filters['priority']))
});
use eval() function
for(var i=0;i<3;i++){
var f=i+1;
eval("if(f==i+1){alert(i);}");
}
Demo: http://jsfiddle.net/ke42b/2/
This is just a tip on how to create dynamic if conditions. Now you know how to create dynamic if conditions.
Code accordingly to your needs !
Related
I am creating an attendance tracker with the jQuery DataTables plugin! I have gotten really far with the functionality/capability and have just been stuck for weeks trying to figure out how to do this last portion of what I want it to do.
I will have a static/workable test case attached below. So the issue that I cannot figure out is how to style the parent rows based off of the child row cell values. The columns Sunday-Friday are colored based off of a hidden value called SundayStatus, MondayStatus, TuesdayStatus, and so on. There are two values that could cause it to turn green (TW & P), two values that could cause it to turn yellow (NR & O), and two values to cause it to turn red (PTO & H). In my rows.every(function ( rowIdx, tableLoop, rowLoop ) { function I need to find a way to manipulate the data and add classes to the parent rows based off the attendance values from each individual day.
P.S.(I created my own plugin $.fn.dataTable.ext.search.push(function to search through all of the data in the table and only show items where the dates Sunday-Friday are dates that are in the current week.
UPDATE 5/10 Andrew was on the right track with the update to his answer, I made one small change to today format, and changed var result = Object.keys(data).find(key => data[key].substring(0,10) === today); to var result = Object.keys(data).find(key => typeof data[key] === 'string' && data[key].startsWith(today));. I then created a conditional in my dynamic code, to read through the result from the reverse-lookup and depending on what the result is, to color the row a certain color.
Here is my JSFiddle of the Static Example that was previously in a snippet within the post: https://jsfiddle.net/BeerusDev/y8t0xoze/19/
In this update, my last and final issue that I am dealing with that I did not foresee, is that everything seems to be working fine, but it appends the status class from the first item that is posted to the DataTable and doesn't take into account for the other items. I have hit a mental block trying to figure out a way around this issue, but here is my rows.every function from my dynamic application which is inside of my startRender function
var statusClass = '';
rows.every(function ( rowIdx, tableLoop, rowLoop ) {
var data = this.data();
var node = this.node();
var today = moment().format("YYYY-MM-DD"); // "05/10/2021"
console.log(today);
//console.log(JSON.stringify(data));
var result = Object.keys(data).find(key => typeof data[key] === 'string' && data[key].startsWith(today)); // "Monday"
console.log(result);
var todayStatus = result ? data[result + 'Status'] : 'n/a';
console.log(todayStatus);
if(todayStatus === "P" || todayStatus === "TW") {
statusClass = 'green';
}
if(todayStatus === "NR" || todayStatus === "O") {
statusClass = 'yellow';
}
if (todayStatus === "PTO" || todayStatus === "H") {
statusClass = 'red';
}
});
//Add category name to the <tr>.
return $('<tr/>').addClass(statusClass)
.append('<td colspan="8">' + group + ' (' + rows.count() + ')</td>')
.attr('data-name', all)
.toggleClass('collapsed', collapsed);
This looks very close, to me!
Here are some changes I recommend:
After the end of your closing </table> tag, there is an extra <body> tag. That looks incorrect - it should be removed. I don't think this causes any errors - but it is worth fixing.
In your rows.every() function, the data variable is a plain array - for example:
[ "IT", "Name 1", "Locations Here", "05/02/2021", "05/03/2021", "P", … ]
Therefore you cannot use data.MondayStatus - because that will be undefined. Instead use something like data[5] to get the 6th item in the array (P).
If you want to change the background color of a row for a location (e.g. "IT" or "OM"), you can use a selector like this:
$("tr[data-name='IT'] td").addClass("green");
This works because you have already added a custom attribute called data-name to the relevant <td> tag. The selector finds the <td> tag which is the child of the <tr> tag using that custom attribute.
However, the problem here is: You are trying to assign the class to a table node before the DataTable has finished being built.
To address this you can move all of that row looping logic to an initComplete function:
initComplete: function(settings, json) {
this.api().rows().every(function ( rowIdx, tableLoop, rowLoop ) {
var data = this.data();
var node = this.node().previousSibling; // to handle your row grouping
if (node !== null) {
if (data[5] === "P") {
var selectorVar = "[data-name='" + data[0] + "'] td";
$( selectorVar ).addClass("green");
}
}
});
}
Instead of if (data[5] === "P"), you can expand this logic to handle different values and also different class names (not just "green"), for whatever the overall logic is that you need. My logic is just a small demo to show the color change.
Update to handle "today"
To show the approach, let's assume the following record:
var data = {
"Department": "IT",
"Name": "Name 1",
"Locations": "Locations Here",
"Sunday": "2021-05-09",
"Monday": "2021-05-10",
"MondayStatus": "P",
"Tuesday": "2021-05-11",
"TuesdayStatus": "Q",
"Wednesday": "2021-05-12",
"WednesdayStatus": "R",
"Thursday": "2021-05-13",
"ThursdayStatus": "S",
"Friday": "2021-05-14",
"FridayStatus": "T"
};
This data variable is what I think you are handling in the rows.every function. So, it's the equivalent of var data = this.data();. I may have got some of the keys wrong (uppercase/lowercase) - but you can adjust the test data if that is the case.
Now, I get today's date, formatted to match the same format as the dates in the data object:
var today = moment().format("YYYY-MM-DD"); // "2021-05-10"
I use this value to find the equivalent value in the data variable, and I return the key name for that entry:
var result = Object.keys(data).find(key => data[key].substring(0,10) === today); // "Monday"
This is basically a reverse-lookup from what you would normally do. Instead of starting with a key, we start with a value and end with a key - in this case, the key is the string "Friday".
Now we take this string and append "Status" to it.
This gives us an actual key string: "FridayStatus".
Now we use that key to find the status for today (if it exists at all in the data object):
var todayStatus = result ? data[result + 'Status'] : 'n/a'; // "P"
If the date does not exist, then you will end up with a status of "n/a".
Overall, this gives us a quick way to get today's status, without having to perform lots of if/else logic.
Once you have today's status you can use it in a smaller if/else to choose the required color you want to apply to the row.
I built a custom component that filters an array of objects. The filter uses buttons, sets from active to non-active and allows more than one option on/off at the same time.
StackBlitz of my attempt - https://stackblitz.com/edit/timeline-angular-7-ut6fxu
In my demo you will see 3 buttons/options of north, south and east. By clicking on one you make it active and the result should include or exclude a matching "location" either north, south and east.
I have created my methods and structure to do the filtering, I'm struggling with the final piece of logic.
So far I have created a method to create an array of filtered locations depending on what the user clicks from the 3 buttons.
Next this passes to my "filter array" that gets the logic that should compare this filtered array against the original to bring back the array of results that are still remaining.
Its not quite working and not sure why - I originally got this piece of functionality working by using a pipe, but fore reasons do not want to go in that direction.
//the action
toggle(location) {
let indexLocation = this.filteredLocations.indexOf(location);
if (indexLocation >= 0) {
this.filteredLocations = this.filteredLocations.filter(
i => i !== location
);
} else {
this.filteredLocations.push({ location });
}
this.filterTimeLine();
}
// the filter
filterTimeLine() {
this.filteredTimeline = this.timeLine.filter(x =>
this.contactMethodFilter(x)
);
}
//the logic
private contactMethodFilter(entry) {
const myArrayFiltered = this.timeLine.filter(el => {
return this.filteredLocations.some(f => {
return f.location === el.location;
});
});
}
https://stackblitz.com/edit/timeline-angular-7-ut6fxu
Sorry for my expression but u have a disaster in your code. jajaja!. maybe u lost that what u need but the logic in your functions in so wrong. comparing string with objects. filter a array that filter the same array inside... soo u need make a few changes.
One:
this.filteredLocations.push({location});
Your are pushing object. u need push only the string.
this.filteredLocations.push(location);
Two:
filterTimeLine() {
this.filteredTimeline = this.timeLine.filter(x =>
this.contactMethodFilter(x)
);
}
in this function you filter the timeLine array. and inside of contactMethodFilter you call filter method to timeLine again....
See a functional solution:
https://stackblitz.com/edit/timeline-angular-7-rg7k3j
private contactMethodFilter(entry) {
const myArrayFiltered = this.timeLine.filter(el => {
return this.filteredLocations.some(f => {
return f.location === el.location;
});
});
}
This function is not returning any value and is passed to the .filter
Consider returning a boolean based on your logic. Currently the filter gets undefined(falsy) and everything would be filtered out
I am working on the stencil platform on big commerce. this platform uses the handlebars syntax. I need to be able to set a value based on one of the parameters in my URL, more that like the 'window.location.pathname', and i need to be able to access this new variable across the site. I am able to make something work two different ways using regular JavaScript, but i do not want to recreate my script in every place throughout the site. So basically, I could use some help getting one of my 2 vanilla scripts into a handlebars for formatting. What i have that works is shown below:
<p id="BrandLogo"></p>
<script>
var directory = window.location.pathname;
var branding;
var str = directory.includes("blackvue");
if (str === false) {
branding = value one;
} else {
branding = value 2
}
document.getElementById("BrandLogo").innerHTML = branding;
</script>
or
<p id="BrandLogo"></p>
<script>
var directory = window.location.pathname;
var branding;
if (str == '/URL-I-Want-To-Focus-On/') {
branding = value one;
} else {
branding = value 2
}
document.getElementById("BrandLogo").innerHTML = branding;
</script>
Thanks in advance
If you are trying to set and use a local variable within handlebars try something like this:
First, create a helper function named 'setVar':
var handlebars = require('handlebars');
handlebars.registerHelper("setVar", function(varName, varValue, options) {
options.data.root[varName] = varValue;
});
Next, set your variable(s) using the function you created in the first step.
{{setVar "greeting" "Hello World!"}}
{{#if some-condition}}
{{setVar "branding" "Value one"}}
{{else}}
{{setVar "branding" "Value 2"}}
{{/if}}
Finally, use the variable(s) on your page:
<div>
<h1 id="BrandLogo">{{greeting}}</h1>
</div>
document.getElementById("BrandLogo").innerHTML = {{branding}};
If you are trying to add a serial number inside a nested 'each' or based on a condition inside nested each following helper works good:
hbs.registerHelper('serialNo', function (options) {
var currentSerialNo = options.data.root['serialNo'];
console.log("############Current serial No is:"+currentSerialNo);
if (currentSerialNo === undefined) {
currentSerialNo = 1;
} else {
currentSerialNo++;
}
options.data.root['serialNo'] = currentSerialNo;
return currentSerialNo;
});
Now inside your template you can simply use it like:
{{serialNo}}
Everytime {{serialNo}} is encountered it prints a serial number one greater than before.
I have the following code in my controller:
$scope.filteredTransactions = $scope.invoiceTransactionsObject.transactions.concat(); // make a copy of the initial array
if ($scope.searchTerm.message)
{
var search = $scope.searchTerm.message;
$scope.filteredTransactions = $filter('filter')($scope.filteredTransactions, ({ message: search } || { item: search }));
}
I want to be able to filter by typing some value and search either in the message column or item column. According to How to filter multiple values (OR operation) in angularJS it should work, but it doesn't and if I type something that can be found in the message, it works, but when I type something from the item, it returns empty array.
Do you see where is my mistake?
Update Deleted irrelevant/mistaken initial answer
Since you're applying $filter inside a JS script, and it doesn't use any of the advanced features of $filter, I'd switch over to the JS-native method of filtering an array:
$scope.filteredTransactions = $scope.invoiceTransactionsObject.transactions.concat(); // make a copy of the initial array
if ($scope.searchTerm.message)
{
var search = $scope.searchTerm.message;
$scope.filteredTransactions = $scope.filteredTransactions.filter(function (trans) {
return trans.message.toLowerCase().indexOf(search) >= 0 || trans.item.toLowerCase().indexOf(search) >= 0;
});
}
...assuming that $filter is case-insensitive and matches anywhere in the string. If that's not the functionality of $filter and/or not what you want, you'd adjust the code accordingly.
I would like to know what is the most elegant and simple way to implement this.
I need to add a filter expression for a ng-repeat that would filter 2 conditions from one property.
In this example http://plnkr.co/edit/OMQxXvSjtuudMRGE4eZ8?p=preview
If you enter A, it would display checkbox for A,
enter B - display checkbox for B.
But I want to display the specified checkboxes plus anything with empty condition.
There is no condition for C, so:
if you enter A, I want to display both A and C checkboxes,
enter B, I want to display both B and C checkboxes.
I would create custom filter like:
app.filter('myfilter', function() {
return function( items, condition) {
var filtered = [];
if(condition === undefined || condition === ''){
return items;
}
angular.forEach(items, function(item) {
if(condition === item.condition || item.condition === ''){
filtered.push(item);
}
});
return filtered;
};
});
and usage:
<span ng-repeat="charge in charges | myfilter:level.condition">
See Demo in Plunker
It looks pretty elegant and clear.
Hope it will help
I think you can do this pretty easily with just a filter expression function on your scope like this;
$scope.filterExpression = function(charge) {
return (!$scope.level || !charge.condition ||
($scope.level.condition.toUpperCase() === charge.condition.toUpperCase()));
}
and call it like this;
<span ng-repeat="charge in charges | filter:filterExpression">
plunkr (corrected)
you can use :
data-ng-repeat="charge in charges | filter:searchText" data-ng-if="filter = searchText.Name"
Use two ng-repeats, one after another:
1st : Filter on anything that has checkbox checked AND has a condition
2nd : Filter on things that don't have conditions