have error
Uncaught TypeError: Cannot read properties of undefined (reading 'getAttribute')
I have a website that needs to use filters. Sort by price. But displays an error
enter image description here
enter image description here
const big_content = document.querySelector('#big_content');
document.querySelector('#sort_low').onclick = function() {
low__high('data-price')
}
document.querySelector('#sort_high').onclick = function() {
high__low('data-price')
};
function low__high(sortType) {
const big_content = document.querySelector('#big_content');
for (let i = 0; i < big_content.children.length; i++) {
for (let j = i; i < big_content.children.length; j++) {
if (+big_content.children[i].getAttribute(sortType) > +big_content.children.length[j].getAttribute(sortType)) {
replaceNode = big_content.replaceChild(big_content.children[j], big_content.children[i])
insertAfter(replaceNode, big_content.children[i])
}
}
}
console.log('Sort by price: low to high');
}
function high__low(sortType) {
const big_content = document.querySelector('#big_content');
for (let i = 0; i < big_content.children.length; i++) {
for (let j = i; i < big_content.children.length; j++) {
if (+big_content.children[i].getAttribute(sortType) < +big_content.children.length[j].getAttribute(sortType)) {
replaceNode = big_content.replaceChild(big_content.children[j], big_content.children[i])
insertAfter(replaceNode, big_content.children[i])
}
}
}
console.log('Sort by price: high to low');
}
function insertAfter(elem, refElem) {
return refElem.parentNode.insertBefore(elem, refElem.nextSibling)
}
I'm trying to access objects properties inside an array in my code to render the text values of input boxes restored after a refresh from the local storage but for some reason when I try to run the for loop inside my appStart() function it gives me: "Uncaught TypeError: Cannot read property 'id' of undefined at appStart". Any insiights of why this happens and how to fix it will be greatly appreciated.
const currentDayPlaceholder = $("#currentDay");
const timeInTimeBlocks = $(".input-group-text");
const timeBlockInput = $(".form-control");
const saveButton = $(".saveBtn");
let numericCurrentTime = parseInt(moment().format("H A"));
let notes = [];
currentDayPlaceholder.append(moment().format('dddd, MMMM Do'));
function timeBlocksColorDeterminator() {
for (let i = 0; i < timeInTimeBlocks.length; i++) {
let numericTimeinTimeBlock = parseInt($(timeInTimeBlocks[i]).text());
if ($(timeInTimeBlocks[i]).hasClass('pm')) {
numericTimeinTimeBlock += 12;
}
if (numericCurrentTime === numericTimeinTimeBlock) {
$(timeBlockInput[i]).addClass("present");
} else if (numericCurrentTime > numericTimeinTimeBlock) {
$(timeBlockInput[i]).addClass("past");
} else {
$(timeBlockInput[i]).addClass("future");
}
}
}
function appStart() {
notes = JSON.parse(localStorage.getItem("timeBlockNotes"));
for (let i = 0; i < timeBlockInput.length; i++) {
if (i === parseInt(notes[i].id)) {
timeBlockInput[i].value = notes[i].value;
}
}
}
appStart();
saveButton.on("click", function () {
console.log("click");
notes.push({
value: timeBlockInput[this.id].value,
id: this.id
})
localStorage.setItem("timeBlockNotes", JSON.stringify(notes));
})
timeBlocksColorDeterminator();
I have fixed this after changing my appStart() function to this :
function appStart() {
notes = JSON.parse(localStorage.getItem("timeBlockNotes"));
for (let i = 0; i < notes.length; i++) {
timeBlockInput[parseInt(notes[i].id)].value = notes[i].value;
}
}
thank you guys for your comments and answers.
Now I want to bind the data responded with function "getPresentationFilterValues" with filterItem.
How can I get the data of filter Item when calling the callback function with promise? Following is the code.
$q.all(presentationPromiseList).then(
function(response){
for(var i=0; i<response.length; i++){
config = self.bindAppPresentation(response[i], {config:config});
var filtering = config.configuration.filtering;
for(var i = 0; i< filtering.length; i++){
for(var j = 0; j < filtering[i].filters.length; j++){
var filterItem = filtering[i].filters[j];
if(filterItem.source == 'dynamic'&& !filterItem.options){
responsePromise = reveal.getPresentationFilterValues(filterItem);
responsePromise.then(function(response){
}).catch(function(ex){});
}
}
}
}
console.log("App presentation bind");
return 'param1';
},
function(response){
return $q.reject(new Error("failed to get app presentation: " + response.data.message));
}
)
Something like this:
const outsideData = 1
someFunctionWhichReturnsPromise().then(function() { return outsideData })
module.filter('myCustomFilter', function ($filter) {
return function(items, searchedTxt, headers) {
if (headers.choice === "option1") {
return resultByDates(items, searchedTxt);
} else if (headers.choice === "option2") {
return resultByName(items, searchedTxt, headers);
}
else if (headers.choice === "option3") {
return resultSimple(items, searchedTxt);
}
return items;
};
function resultByDates(items, search) {
if (search === undefined || search === null)
return items;
var k = Object.keys(search)[0];
var i;
for (i = 0; i < items.length; i++) {
items[i][k] = $filter('date')(items[i][k], "MM/dd/yyyy");
}
var filteredData = $filter('filter')(items, search);
var indexes = [];
for (i = 0; i < filteredData.length; i++) {
indexes.push(items.indexOf(filteredData[i]));
}
var output = [];
for (i = 0; i < indexes.length; i++) {
output.push(items[indexes[i]]);
}
return output;
}
function resultByName(items, search, headers) {
if (search === undefined || search === null)
return items;
if (headers !== undefined) {
var k = Object.keys(search)[0];
var i;
var componentVals = headers.componentVals;
var itemsCopy = angular.copy(items);
for (i = 0; i < items.length; i++) {
for (var obj in componentVals) {
if (componentVals[obj].ID === itemsCopy[i][k]) {
itemsCopy[i][k] = componentVals[obj].Name;
break;
}
}
}
var filteredData = $filter('filter')(itemsCopy, search);
var indexes = [];
for (i = 0; i < filteredData.length; i++) {
indexes.push(itemsCopy.indexOf(filteredData[i]));
}
var output = [];
for (i = 0; i < indexes.length; i++) {
output.push(items[indexes[i]]);
}
return output;
}
return items;
}
function resultSimple(items, search) {
if (search === undefined || search === null)
return items;
return $filter('filter')(items, search);
}
});
Guys, I have above filter which works - partially, Option1 and Option3 returns correct filtered data, but there is some problem with Option2.
When I filter data with Option1 it returns correctly filtered data, then I can additionally filter with Option3 and it filters incorrectly returned previously data. When I use Option2 it seems like the data is being returned is not binded with the previous return, it's returning separate data.It seems like it is a separate collection... Is there something wrong with the way I return data in Option2?
Hope I have explained problem sufficiently. Thanks.
Below version with some fixes suggested by Himmel.
module.filter('myCustomFilter', function ($filter) {
return function (items, searchedTxt, headers) {
var key;
var i;
var indexes;
var filteredData;
var output;
if (headers.choice === "option1") {
key = Object.keys(searchedTxt)[0];
for (i = 0; i < items.length; i++) {
items[i][key] = $filter('date')(items[i][key], "MM/dd/yyyy");
}
filteredData = $filter('filter')(items, searchedTxt);
indexes = [];
for (i = 0; i < filteredData.length; i++) {
indexes.push(items.indexOf(filteredData[i]));
}
output = [];
for (i = 0; i < indexes.length; i++) {
output.push(items[indexes[i]]);
}
return output;
} else if (headers.choice === "option2") {
key = Object.keys(searchedTxt)[0];
var componentVals = headers.componentVals;
var itemsCopy = angular.copy(items);
for (i = 0; i < items.length; i++) {
for (var obj in componentVals) {
if (componentVals[obj].ID === itemsCopy[i][key]) {
itemsCopy[i][key] = componentVals[obj].Name;
break;
}
}
}
filteredData = $filter('filter')(itemsCopy, searchedTxt);
indexes = [];
for (i = 0; i < filteredData.length; i++) {
indexes.push(itemsCopy.indexOf(filteredData[i]));
}
output = [];
for (i = 0; i < indexes.length; i++) {
output.push(items[indexes[i]]);
}
return output;
} else if (headers.choice === "option3") {
return $filter('filter')(items, searchedTxt);
}
return items;
};
});
I have finally figured out the problem… So when I filtered with Option3 there was no issue because I didn’t modify collection before filtering, after when I filtered with Option1 I did mods to the collection because I wanted to filter based on displayed formatted date. Finally when I used Option3 I was only modifying collection for needs of current Option3 filter – without considering that before filtering I should consider mods that I have done during Option2 filtering. To confirm/test I have created a global array which holds my modified collection, so every time I’m filtering with any of the options I’m using that global array. It’s very dirty temporary solution but it works. Hope I clarified this problem enough. Is there a better solution?
It seems like you're trying to combine learning JavaScript and Angular at the same time, tough times!
module.filter('myCustomFilter', function ($filter) {
// You probably aren't trying to return "function", here
return function(items, searchedTxt, headers) {
if (headers.choice === "option1") {
return resultByDates(items, searchedTxt);
} else if (headers.choice === "option2") {
return resultByName(items, searchedTxt, headers);
}
else if (headers.choice === "option3") {
return resultSimple(items, searchedTxt);
}
return items;
};
// are you declaring another function after you've returned?
function resultByDates(items, search) {
if (search === undefined || search === null)
return items;
var k = Object.keys(search)[0];
var i;
for (i = 0; i < items.length; i++) {
items[i][k] = $filter('date')(items[i][k], "MM/dd/yyyy");
}
var filteredData = $filter('filter')(items, search);
var indexes = [];
for (i = 0; i < filteredData.length; i++) {
indexes.push(items.indexOf(filteredData[i]));
}
var output = [];
for (i = 0; i < indexes.length; i++) {
output.push(items[indexes[i]]);
}
return output;
}
// another??
function resultByName(items, search, headers) {
if (search === undefined || search === null)
return items;
if (headers !== undefined) {
var k = Object.keys(search)[0];
var i;
var componentVals = headers.componentVals;
var itemsCopy = angular.copy(items);
for (i = 0; i < items.length; i++) {
for (var obj in componentVals) {
if (componentVals[obj].ID === itemsCopy[i][k]) {
itemsCopy[i][k] = componentVals[obj].Name;
break;
}
}
}
var filteredData = $filter('filter')(itemsCopy, search);
var indexes = [];
for (i = 0; i < filteredData.length; i++) {
indexes.push(itemsCopy.indexOf(filteredData[i]));
}
var output = [];
for (i = 0; i < indexes.length; i++) {
output.push(items[indexes[i]]);
}
return output;
}
return items;
}
// christ!!
function resultSimple(items, search) {
if (search === undefined || search === null)
return items;
return $filter('filter')(items, search);
}
});
So, the first line, function($filter) {... is the function that is "invoked" when the list filter is triggered. The value that it returns will be the values that constitute the new list.
So if you "return" [1, 2, 3, 4] you will see those in the list in the browser. But if your function immediately returns a "function" instead of a "list" ([]), well then the browser will probably do something weird with it...
Oh wait, you're calling a bunch of functions that are outside of the current function you're in. Probably remove resultByDates from the current function call, as well as resultByName..., put them as siblings to module.filter.
This question is very hard to fix with so many issues, can you isolate a simpler problem? Maybe a small piece of unexpected behavior?
Could you please tell me how to make from this 4 functions just 1. Cause they all do one thing, with just one parameter changing all the time.
Also, I need to take the value of each time the function is running and put it into a new variable so I can after calculate it.
function getValue(age)
{
for (var i = 0; i < document.getElementsByName('age').length; i++)
{
if (document.getElementsByName('age')[i].checked)
{
return document.getElementsByName('age')[i].value;
}
}
}
function getBmiValue()
{
for (var i = 0; i < document.getElementsByName('bmi').length; i++)
{
if (document.getElementsByName('bmi')[i].checked)
{
return document.getElementsByName('bmi')[i].value;
}
}
}
function getFamValue()
{
for (var i = 0; i < document.getElementsByName('fam').length; i++)
{
if (document.getElementsByName('fam')[i].checked)
{
return document.getElementsByName('fam')[i].value;
}
}
}
function getDietValue()
{
for (var i = 0; i < document.getElementsByName('diet').length; i++)
{
if (document.getElementsByName('diet')[i].checked)
{
return document.getElementsByName('diet')[i].value;
}
}
}
function getValueByElementName(element_name)
{
for (var i = 0; i < document.getElementsByName(element_name).length; i++)
{
if (document.getElementsByName(element_name)[i].checked)
{
return document.getElementsByName(element_name)[i].value;
}
}
}
Or a little bit optimization:
function getValueByElementName(element_name)
{
var elements = document.getElementsByName(element_name);
for (var i = 0; i < elements.length; i++)
{
if (elements[i].checked)
return elements[i].value;
}
}
function getValue(tagname)
{
for (var i = 0; i < document.getElementsByName(tagname).length; i++)
{
if (document.getElementsByName(tagname)[i].checked)
{
return document.getElementsByName(tagname)[i].value;
}
}
}
Pass your element name as a variable in this function and call it.
Here is an example of what you can do:
function getValue(key) {
// get this once, not on each loop iteration
var elem = document.getElementsByName(key);
// cache the length too, so not to calculate it on each loop iteration
for (var i = 0, len = elem.length; i < len; i++) {
if (elem[i].checked) {
return elem[i].value;
// this will exit the function when it finds the FIRST one.
// Is that what you want?
}
}
}
// you can call above function like this:
getValue('age');
getValue('bmi');
getValue('fam');
getValue('diet');