JS finding the IndexOf() a substring within a string - javascript

I'm using React to build a restaurant violation app, and I'm trying to return results where the searched term is a substring of the data set. However, I'm getting an error message saying;
ViolationsRequest.jsx:49 Uncaught TypeError: Cannot read property 'indexOf' of null.
Based on my tests, it looks like door.restaurant is being console-logged as undefined. Strangely enough, this code works as an exact match, i.e., if you switch out the if block as:
if (this.props.restaurant == door.restaurant) {
This is my code block.
const violationElements = this.state.doors.map((door, idx) => {
if (door.restaurant.indexOf(this.props.restaurant) !== -1) {
console.log();
return (
<ViolationsView key={idx}
restaurant={door.restaurant}
building={door.building}
street={door.street}
zip={door.zip}
phone={door.phone}
cuisine={door.cuisine}
inspectionDate={door.inspectionDate}
action={door.action}
violationCode={door.violationCode}
violationDescription={door.violationDescription}
criticalFlag={door.criticalFlag}
score={door.score}
grade={door.grade}
gradeDate={door.gradeDate}
inspectionType={door.inspectionType}
/>
)
}
});
This is my state.doors array:
const cleanData = restaurantData.data.map((inspectionData) => {
const [sid, id, position, createdAt, createdMeta,
updatedAt, updatedMeta, meta, camis, dba, boro,
building, street, zipcode, phone, cuisine,
inspectionDate, action, violationCode,
violationDescription, criticalFlag, score, grade,
gradeDate, recordDate, inspectionType] = inspectionData;
return {
sid: sid,
restaurant: dba,
building: building,
street: street,
zip: zipcode,
phone: phone,
cuisine: cuisine,
inspectionDate: inspectionDate,
action: action,
violationCode: violationCode,
violationDescription: violationDescription,
criticalFlag: criticalFlag,
score: score,
grade: grade,
gradeDate: gradeDate,
inspectionType: inspectionType,
};
});

One of your doors.restaurant is null, which is what the error message states. Null, not undefined. If it was undefined the error message would have said so. When you call doors.restaurant.indexOf on this value it returns an error.
As I type this, you seem to have already figured it out.

I think the problem is you aren't using the === operator, so with the == you are validating only value not type.
Example:
var foo = null;
var bar = '';
var baz = 0;
var off = {};
console.log(bar == baz); // true
console.log(bar === baz); // false
console.log(foo == off.bar); // true
console.log(foo === off.bar); // false
so probably this.props.restaurant == door.restaurant is true
but this.props.restaurant === door.restaurant is false

Related

Conditional statement for testing an empty object not executing

I'm trying to show a success feedback once the users are registered without error. There is an errors redux reducer object which stores errors that come from the back end. And the if statement is supposed to give the success feedback if the errors object is empty, it displays the errors if there are any, it also registers the users if there is none, but it doesn't seem to execute the if(props.errors === {}) block.
function onSubmit(e) {
e.preventDefault();
const newUser = {
fname: fname,
lname: lname,
phone: phone,
email: email,
password: password,
};
dispatch(register(newUser));
if (props.errors === {}) { //This block is not executed
setSnackOpen(true);
setFname('');
setLname('');
setEmail('');
setPhone('');
setPassword('');
}
console.log('errors :' + props.errors); //logs 'errors : [object, object]'
}
The errors reducer:
import { GET_ERRORS } from '../actionTypes/actionTypes';
const initialState = {
};
export const errorReducer = (state = initialState, action) => {
switch (action.type) {
case GET_ERRORS:
return action.payload
default:
return initialState;
}
};
Because you are comparing props.errors with {} new empty object so even though both are empty they are pointing to different memory location so if condition will return false for the statement if(props.errors === {})
You can check length of the props.errors like
if(!Object.keys(props.errors).length)
Every time you declare a new object(empty or not), it will be created with a new reference. you can run below code in you dev console. all of them will give the result false. Because obj1 is a different empty object than obj2.
var obj1 = {}
var obj2 = {}
console.log(obj1 === {})
console.log(obj2 === {})
console.log(obj1 === obj2)
false
false
false
One way to check if an object is empty is this:
Object.keys(obj1)
This will give you an array of key values from object.
so, you can check the length of the array.
const keysArray = Object.keys(obj1)
if (keysArray.length === 0){
// do something
}
This if (props.errors === {}) would never be true, as it's actually comparing their references, which are not the same.
And I would do as below, and the advantage is that it would work both for when there isn't any key, as well as for when there are some, but their values are empty.
if (!Object.keys(props.errors).some((k) => props.errors[k]))
It's helpful for when you consider {firstNameError:"", lastNameError:"" } and {} as empty. See the snippet below:
const objOne={firstNameError:"", lastNameError:"" };
const objTwo= {};
if(!Object.keys(objOne).length){
console.log("First console prints empty")
}
if (!Object.keys(objOne).some((k) => objOne[k])){
console.log("Second console prints empty")
}
if(!Object.keys(objTwo).length){
console.log("First console prints empty")
}
if (!Object.keys(objTwo).some((k) => objTwo[k])){
console.log("Second console prints empty")
}

Using Conditional Check on Empty Object Before Network Request in Angular App

I have a function that takes in filter values and the passes a network request in my Angular app. Because I'm running into issues where the network request is made before the filters arrive, I've tried setting up some conditional checks to not make the network request until the filter values are available. It's not the ideal solution, but I'm trying to get something working (for now) on short notice.
This is my code. First, I set up a function to check if an object is empty or not. I do this because I want to only fire my network request once I have a non-empty object. And the object will be non-empty once the filter values have been applied. Here's the code:
isEmptyObj(obj) {
return Object.keys(obj).length === 0;
}
public async onFilterReceived(values) {
let filters = {};
if (!values) return;
if (values) {
filters = values;
}
this.route.params.subscribe(
(params: any) => {
this.page = params['page'];
}
);
let fn = resRecordsData => {
this.records = resRecordsData;
};
// Make request IF filters is NOT empty object (i.e. it has values)
if (!this.isEmptyObj(filters)) {
console.log('filter values within cond call: ', filters); // should not be empty
console.log('firstName within cond call: ', filters['firstName']); // should not be empty in this case as I selected a firstName value
console.log('should be false: ', this.isEmptyObj(filters)); // should be false
this.streamFiltersService.getByFilters(
this.page - 1, this.pagesize, this.currentStage, this.language = filters['language'], this.location = filters['location'],
this.zipcode = filters['zip'], this.firstName = filters['firstName'], this.lastName = filters['lastName'],
this.branch = filters['branch'], fn);
}
}
Clearly this is not working as intended. When I look at what logs to the console from WITHIN the conditional section, I see 'filters' and 'firstName' as empty values. In other words, my conditional check is not working as I intended it to. What am I missing here? How could I approach this differently so that the network request is only made once I have the values?
By the way, when I console.log values, this is what I get:
{zip: Array(0), firstName: Array(0), lastName: Array(0), language: Array(0), location: Array(0), …}
By the way, earlier console logs I used demonstrate that initially filters is an empty object. It's only I assign values to filters that it is no longer an empty object.
So, why then is my conditional check before the network request working as intended?
Within the if conditional I see this console.log:
filter values within cond call: {zip: Array(0), firstName: Array(0), lastName: Array(0), language: Array(0), location: Array(0), …}
Help me understand how this is happening based on my above code.
The first issue is that the method isEmptyObj(obj) to check for keys isn't working as you are expecting. This is because the sample values you provided:
{zip: Array(0), firstName: Array(0), lastName: Array(0), language: Array(0), location: Array(0), …}
Even though it is only empty arrays, that still has keys, so that method isEmptyObj will return false for that sample value. The only time it would return false would be for a plain empty object {}.
function isEmptyObj(obj) {
return Object.keys(obj).length === 0;
}
console.log(isEmptyObj({}));
console.log(isEmptyObj({ zips: [] }));
So change that to something like where you filter "falsy" values based on length:
function isEmptyObj(obj) {
return Object.keys(obj).map(key => obj[key]).filter(v => v.length > 0).length === 0;
}
console.log(isEmptyObj({ }));
console.log(isEmptyObj({ zip: [] }));
The next issue is the flow of onFilterReceived. It does not need to be an async, method, also this.route.params.subscribe() will effectively always execute after the rest of the code in the method. Try the following by moving everything into subscribe() at the very minimum. Keep in mind you need to subscribe() to an HTTP calls to actually get them to execute:
public onFilterReceived(values) {
let filters = {};
if (!values) return;
if (values) {
filters = values;
}
this.route.params.subscribe((params: any) => {
this.page = params['page'];
let fn = resRecordsData => (this.records = resRecordsData);
// Make request IF filters is NOT empty (i.e. it has values)
if (!this.isEmptyObj(filters)) {
this.streamFiltersService.getByFilters(
this.page - 1, this.pagesize, this.currentStage, this.language = filters['language'],
this.location = filters['location'],
this.zipcode = filters['zip'], this.firstName = filters['firstName'], this.lastName = filters['lastName'],
this.branch = filters['branch'],
fn
)
.subscribe(results => console.log(results));
}
});
);
}
You can use operators such as switchMap, takeWhile, and tap to streamline the Observable portion:
import { switchMap, takeWhile, tap } from 'rxjs/operators';
// ..
public onFilterReceived(values) {
let filters = {};
if (!values) return;
if (values) {
filters = values;
}
this.route.params.pipe(
tap((params: any) => this.page = params['page']),
takeWhile(_ => !this.isEmptyObj(filters)),
switchMap((params: any) => {
let fn = resRecordsData => (this.records = resRecordsData);
return this.streamFiltersService.getByFilters(
this.page - 1, this.pagesize, this.currentStage, this.language = filters['language'],
this.location = filters['location'],
this.zipcode = filters['zip'], this.firstName = filters['firstName'], this.lastName = filters['lastName'],
this.branch = filters['branch'],
fn
);
});
).subscribe(results => console.log(results));
}
Hopefully that helps!

How to check two objects for difference in values in JS?

I want to edit a existing user in Node. My front-end is in pug.
My user table has lots of fields (about 20 to 25), and some have to be unique, like email and username, which I have functions to check if they are not a duplicate.
I only want to update values that has changed on the client, my edit form already has the values of the user of course.
I thought the best way to achieve this is to check all the inputs from req.body, and if it is different from any user values, I should update it. (Perhaps any different methods? Can't I check if the inputs are 'dirty'?)
This could be the situation. Note the req.body object, with values that my user table doesn't have, like password_confirm
req.body = {
username: 'test',
email: 'user#user.com',
password: '1234',
password_confirm: '1234',
location: 'New York',
website: 'new-website.com',
bio: undefined,
expertise: 'New expertise'
}
user = {
username: 'test',
email: 'user#user.com',
password: '1234',
location: 'San Fransico',
website: 'website.com',
bio: null,
expertise: null
}
I now only want to update the changed location, website and expertise fields. I tried many things, using reduce and lodash, but I can't get the fields that I'm looking for.
NB
I already checked different StackOverflow questions but nothing seems to work for my situation..
From what I understood from your question, give this a try,
Object.keys(req.body).forEach((key)=>{
if(user[key] && user[key]!=req.body[key]){
user[key] = req.body[key];
}
})
Well, I think you are over complicating. You don't even need lodash for this.
Object.assign({}, user, req.body);
would work, since you said yourself that you can have different fields in req.body.
If you need diff object use this:
function diff(oldObject, newObject) {
const diff = {};
Object.keys(oldObject).forEach((key) => {
if (oldObject[key] != newObject[key] && newObject[key] !== undefined) {
diff[key] = newObject[key];
}
});
return diff;
}
var body = {
username : 'test',
email : 'user#user.com',
password : '1234',
password_confirm : '1234',
location : 'New York',
website : 'new-website.com',
bio : undefined,
expertise : 'New expertise'
}
var user = {
username : 'test',
email : 'user#user.com',
password : '1234',
location : 'San Fransico',
website : 'website.com',
bio : null,
expertise : null
}
function diff(oldObject, newObject) {
const diff = {};
Object.keys(oldObject).forEach((key) => {
if (oldObject[key] != newObject[key] && newObject[key] !== undefined) {
diff[key] = newObject[key];
}
});
return diff;
}
console.log(diff(user, body));
I figured it out.
Based on #ponary-kostek & #anuragasaurus 's answer, this is what worked for me:
const differences = {};
Object.keys(req.body).forEach((key)=> {
if(req.body[key].length == 0) req.body[key] = null;
if(stakeholder.hasOwnProperty(key) && stakeholder[key]!=req.body[key]){
differences[key] = req.body[key];
}
});
This returns an object with the changed keys and their values.
Because the fields from my user object are retrieved from a SQL DB, they are null. Also, empty body fields are not undefined, but strings. Meaning if the input is empty, it is an empty string, and to compare it to my user object it should first be null.
Thanks everyone for their answers.

Codeacademy contact list building 7/8... Not returning contact info

i'm doing the codeacademy class section "building a contact list" .. what is wrong here? keep getting error "Oops, try again. It looks like your search function doesn't return contact information for Steve."
(http://www.codecademy.com/courses/javascript-beginner-en-3bmfN/0/7)
var friends = {};
friends.bill = {
firstName: "Bill",
lastName: "Gates",
number: "(206) 555-5555",
address: ['One Microsoft Way', 'Redmond', 'WA', '98052']
};
friends.steve = {
firstName: "Steve",
lastName: "Jobs",
number: "(556) 555-5555",
address: ['178 martio', 'cocoa', 'CA', '95074']
};
var list = function(friends) {
for (var key in friends) {
console.log(key);
}
};
var search = function(friends) {
for (var key in friends) {
if (friends[key].firstName === "Bill" || friends[key].firstName === "Steve") {
console.log(friends[key]);
return friends[key];
} else {
console.log("couldn't find them");
}
}
};
The error is in the search function:
The instructions tell you:
Define a function search that takes a single argument, name. If the
argument passed to the function matches any of the first names in
friends, it should log that friend's contact information to the
console and return it.
In a nutshell, it is asking you to create a function where you provide the name of the person you are searching, while you are providing friends which is also a global variable.
The goal of the exercice seems to be that by using:
search("steve");
you should get as a result:
Object :
{ firstName: 'Steve',
lastName: 'Jobs',
number: '(556) 555-5555',
address: [ '178 martio', 'cocoa', 'CA', '95074' ] }
In your (current) search function you will get a result not from the needle (the search parameter) but from your own preferences, defined in your if condition:
if (friends[key].firstName === "Bill" || friends[key].firstName === "Steve")
Hence, what we are going to do, is:
set name as parameter
loop the friends global variable
check if friends[key].firstName is equal to the needle provided (name).
if so, we log it and return it.
Put all together:
var search = function(name) { // <-- note the name instead of friends.
for (var key in friends) {
if (friends[key].firstName === name) { // <-- note that if
console.log(friends[key]);
return friends[key];
} else {
console.log("couldn't find them");
}
}
};
And you're done!
http://prntscr.com/7kth5t
Good try anyway, you were pretty close to the solution.
If you still have any problem or need any clarification feel free to comment.
Use for listing:
list(friends);
and for search:
search(friends);

Check if property is not undefined

I'm building a node+express app and I'm filling an object with JSON that's submitted from a form in the frontend. This works, unless I leave a field empty in the form so that e.g. req.body.address.street is empty/undefined.
This will result in the error:
TypeError: Cannot read property 'street' of undefined
var b = new Business({
name: req.body.name,
phone: req.body.phone,
address: {
street: req.body.address.street,
postalCode: req.body.address.postalCode,
city: req.body.address.city
},
owner: {
email: req.body.owner.email,
password: req.body.owner.password
}
});
My question is how I can best prevent my app from crashing when values are empty. I would like to avoid manually checking each and every property in my app against undefined.
I'm wondering what the best practice is for this common issue.
I don't know if you use jQuery in your project, but if you do, you can create a mask:
// creating your object mask
var req = {
body: {
name: '',
phone: '',
address: {
street: '',
postalCode: '',
city: ''
},
owner: {
email: '',
password: ''
}
}
}
And then, you simply use the jQuery "extend" method (req2 is your submmited object):
$.extend(true, req, req2);
I've create this fiddle for you!
-
Update
Nothing related to your question, but I've just noticed that you're passing an object with a similar structure of req.body to the Business class. However, there is no need to copy property by property manually - you can make, for example, a simple copy of req.body to pass as parameter:
var b = new Business($.extend({}, req.body));
or
var b = new Business(JSON.parse(JSON.stringify(req.body)));
You can't, really. You have two options;
Use a try/ catch:
try {
var b = new Business({
//
});
} catch (e) {
// Something wasn't provided.
}
... or you can define a helper function:
function get(path, obj) {
path = path.split('.');
path.shift(); // Remove "req".
while (path.length && obj.hasOwnProperty(path[0])) {
obj = obj[path.shift()];
}
return !path.length ? obj : null;
}
... you could then replace your use of req.body.address.street etc. with get('req.body.address.street', req).
See a demo here; http://jsfiddle.net/W8YaB/

Categories