I just spent an hour searching for how I could have gotten an
Uncaught TypeError: Cannot set properties of null
javascript. I checked the spelling of the element whose property I was trying to set and knew that element wasn't null because the spelling was the same in the code as in the HTML. I also knew my element was loading, so it wasn't that either.
Turns out no, the element was null. I was trying to set " NameHere" when the element's actual name was "NameHere".
Off by a single space. No wonder I thought the spelling was the same—because all the non-whitespace was identical. (No, the quotation marks slanting in the second NameHere and being totally vertical in the first NameHere wasn't a part of the error, I am typing them all vertical and either Lemmy or my instance is "correcting" them to slanted for the second NameHere. But that is also another tricky-to-spot text difference to watch out for!)
And what did not help is that everywhere I specifically typed things out, I had it correct with no extra spaces. Trying to set " NameHere" was the result of modifying a bunch of correct strings, remembering to account for a comma I put between them, but not remembering to account for the space I added after the comma. In short, I only ever got to see " NameHere" written out in the debugger (which is how I caught it after like 30 repeats of running with the debugger), because everywhere I had any strings written out in the code or the HTML it was always written "NameHere".
I figured I'd post about it here in case I can help anyone else going crazy over an error they did not expect and cannot figure out. Next time I get a similar error I will not just check spelling, I'll check everything in the name carefully, especially whitespace at the beginning and end, or things one space apart being written with two spaces instead. Anyone else have a similar story to save the rest of us some time?
I mean, it's hard to tell why you're doing what you're doing there. Sometimes with JavaScript and frontend code, certain crimes are just a necessary evil.
But yes, I am calling it a crime to concatenate strings and decompose them afterwards.
For one, human errors like what you did are possible.
You could mildly improve on that by pulling out two functions:
encode_blah_list_to_string()
decode_blah_list_from_string()
You could then at least define those directly below each other in the code, making it easy to define them, so they work together.
If you've already looked into unit tests, this would also be an incredibly easy and useful unit test to write. In your test code, you would define a list, then call the encode-function, take the result of that and call the decode-function, and then the result of that should be identical to the original list.
Having said that, encoding things as a string with custom logic like that, has another big problem:
It could happen that e.g.
stringTwo
contains "Hello, World". Suddenly, you'd be splitting in the middle ofstringTwo
, when you're decoding.So, ideally you can avoid it completely and pass around the array directly.
If you can't, the next best thing would be to encode it in JSON. It will handle all these edge cases, and it's a clearly defined way of encoding and decoding, so you wouldn't even need to pull it out into functions.
If it's some custom format that you display to the user (and ideally the user is aware that commas are bad), then yeah, you would have to do the custom encoding and decoding implementation, like described above.
Alright, so if it's a string where it matters that it's spelled exactly correctly and it will be used in more than one place in your codebase, then I would always pull it out into a constant.
If it's an unchanging value that you just pass to a library in one place in your code, like a timezone name, then I wouldn't usually pull it out into a constant, unless I feel like it helps to make this constant clearly visible at the top of the file.
For example, it rarely happens that a constant is unquestionably correct and unchanging, so making your choice prominently visible can be useful. Of course, if you're not running in a browser, then these kind of arbitrarily chosen 'constants' should probably be configurable in a configuration file.
If it's a UI description text, then it might make sense to pull it out into a constant, just to unclutter your code.
Or if you're working with a localization framework, then you'd have pseudo-constants for that anyways, which would get replaced with the respective language text at runtime.
But yeah, I definitely wouldn't say you should always go for constants. They add a layer of indirection, meaning someone reading your code won't know what the actual string is without checking the constant.
But if it needs to be the same value in two places, then this layer of indirection is definitely worth it and makes it easier to reason about your code.
I will also say that if we weren't talking about JavaScript, I would be much more contrarian to strings. Partially because JS is used in frontend a lot, where you do need to deal with strings anyways. And partially, because JavaScript is dynamically typed, so it just doesn't have as many tools to deal with strings otherwise.
In our backend Rust codebase at work, I do tell our juniors, if you're typing a quotation mark and you're not doing it for logging or error messages, then do consider, if that's really what you want. Usually, they want an enum instead, or if they really do need to pass around a string, then they should use a newtype, which is basically a typed wrapper, so you can't accidentally pass the wrong kind of string into a function.
It is JavaScript!
I wanted to say just thank you so much for your feedback and help, I really appreciate it. I'll probably try to handle it as an array until final display to the user (tbh probably just me), where the commas and spaces will be used because that's how English works and seeing an output of
stringOne,stringTwo,stringThree
without the space would just irritate me a lot.I am aware of unit testing and know I should use it. I also didn't use any frameworks and I'm not sure what I should use to test it when I didn't use Node.js or React or anything like that (not sure if "framework" is the right word). My only knowledge of them is that sometimes when I fork other peoples' projects I have to do stuff like
npm install
andnpm run build
and I have a vague overview idea of what those commands do (install dependencies, compile the stuff and run it). What I actually did to test things was just using the website. I let it go because it is small, under 200 lines of code, and probably will not expand very much.Specifically the actual JS never has the string written down! I grab it from the HTML. Where it does show up several times: the element's name, ID (wonder if I can just wipe it out of the name), often its value, and in the element's label in the for attribute. Not sure what best practice is here.
Yeah, sounds good. If you can keep it as an array and only have to encode it for displaying, that's great. It's only when you start decoding again, when the format starts to matter a lot.
I would say it is. React is definitely a framework. Node.js is almost even a platform, because it also includes a runtime, but it also includes a framework, which is the relevant part that you're talking about.
There's no real good definition of "framework". Sometimes what people mean by that, is just a very big library, which has so many tools that your code is entirely reliant on it.
A definition, which I find is also often fitting, is that a framework takes over the control flow. Unlike a library, where you're the one calling library functions, a framework calls your code.
I mean, that is probably fine.
Someone else (including future you) coming across the code would probably curse you for not documenting any of the intended behavior, but at 200 lines, you might have relatively little complex code.
But yeah, that's how you should think of unit testing, it's a specification documenting intended behavior. With the added bonus that it can automatically verify that your code meets this specification.
Having said that, I would absolutely recommend not letting it go. A small project like that is fantastic to learn how to do the whole project setup.
If you find out how to integrate a package manager / build tool like
npm
with this project, then you'll be able to tackle a bigger project next time around, because you can easily use JS libraries.And if you then also find out how to use a unit testing library, like
jest
, your projects can become even bigger, because there's less code you have to manually test (nor manually specify intended behavior).For
npm
, you might want to look up a separate tutorial. Their Getting Started guide talks about creating a user account and whatnot, which you don't need, unless you want to publish libraries.For
jest
, their Getting Started guide looks pretty decent: https://jestjs.io/docs/getting-startedHTML is definitely less crucial to deduplicate. It kind of is like a load of constants defined in one place. When writing HTML, you want to try to choose the IDs, so that they remain unique and meaningful without having to change them all the time. But yeah, that will come with experience.
If someone decides to change an ID in HTML, then they need to be aware that they need to change it everywhere else, too. If you've done a good job giving it a rather unique name, it will also be trivial to do a text search across the whole project for it, and have it replaced everywhere.
If you do ever truly need to deduplicate HTML, there's various templating libraries available, but that's definitely not worth the overhead for deduplicating IDs.
Wait no, I never had to change IDs. They are all unique and have been since I first defined them. I meant that the ID attribute of my element is the same as its name attribute and also its value attribute. Does any of the advice change given this?
Thank you!