<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Daniel Cobo | 👨‍💻 Full-stack developer |🍦Vanilla code advocate ]]></title><description><![CDATA[Daniel Cobo | 👨‍💻 Full-stack developer |🍦Vanilla code advocate ]]></description><link>https://danielcobo.com</link><generator>RSS for Node</generator><lastBuildDate>Sun, 12 Apr 2026 13:03:10 GMT</lastBuildDate><atom:link href="https://danielcobo.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Bulletproof type checks in JavaScript]]></title><description><![CDATA[Using typeof
To check what type is a variable you would most likely use the typeof function. You can even skip the parenthesis (typeof someVariable is same as typeof(someVariable)).
typeof works great for:

strings
numbers (not if checking integer vs...]]></description><link>https://danielcobo.com/bulletproof-type-checks-in-javascript</link><guid isPermaLink="true">https://danielcobo.com/bulletproof-type-checks-in-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[data]]></category><dc:creator><![CDATA[Daniel Cobo]]></dc:creator><pubDate>Mon, 17 May 2021 21:31:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1621286886045/eYlgvlBth.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="using-typeof">Using typeof</h2>
<p>To check what type is a variable you would most likely use the <code>typeof</code> function. You can even skip the parenthesis (<code>typeof someVariable</code> is same as <code>typeof(someVariable)</code>).</p>
<p><code>typeof</code> works great for:</p>
<ul>
<li>strings</li>
<li>numbers (not if checking integer vs. float)</li>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt">big integers</a></li>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Symbol">symbols</a></li>
<li>functions </li>
<li>booleans</li>
<li>checking if a variable is undefined</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">typeof</span> <span class="hljs-string">"hello"</span>; <span class="hljs-comment">//string</span>

<span class="hljs-keyword">typeof</span> <span class="hljs-number">1</span>; <span class="hljs-comment">//number</span>
<span class="hljs-keyword">typeof</span> <span class="hljs-number">0.1</span>; <span class="hljs-comment">//number</span>

<span class="hljs-keyword">typeof</span> <span class="hljs-number">10000000000000000000000000n</span>; <span class="hljs-comment">//bigint</span>

<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">Symbol</span>(<span class="hljs-string">"SomeSymbol"</span>); <span class="hljs-comment">//symbol</span>

<span class="hljs-keyword">typeof</span> <span class="hljs-literal">true</span>; <span class="hljs-comment">//boolean</span>
<span class="hljs-keyword">typeof</span> <span class="hljs-literal">false</span>; <span class="hljs-comment">//boolean</span>

<span class="hljs-keyword">typeof</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{}; <span class="hljs-comment">//function</span>

<span class="hljs-keyword">typeof</span> iamundefined <span class="hljs-comment">//undefined</span>
</code></pre>
<p>It kinda sucks if you need to check:</p>
<ul>
<li>arrays</li>
<li>integer</li>
<li>floating number</li>
<li><code>null</code></li>
<li><code>NaN</code></li>
<li>regex</li>
<li>a date object</li>
<li>a custom object</li>
</ul>
<p>👑 Keep calm and check the solutions below 👍</p>
<h2 id="check-if-a-variable-is-an-array">Check if a variable is an array</h2>
<p>The use built-in <code>.isArray</code> method will return true/false if the value is an array. This is way better than the old school method of duck typing when you had to check if the variable is an object and has the <code>.length</code> property.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">Array</span>.isArray([]); <span class="hljs-comment">// true</span>
</code></pre>
<h2 id="check-if-a-variable-is-an-integer">Check if a variable is an integer</h2>
<p>The <code>Number.isInteger</code> method returns true if the variable is an integer.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">Number</span>.isInteger(<span class="hljs-number">1</span>); <span class="hljs-comment">//true</span>
<span class="hljs-built_in">Number</span>.isInteger(<span class="hljs-number">0.1</span>); <span class="hljs-comment">//false</span>
<span class="hljs-built_in">Number</span>.isInteger(<span class="hljs-number">1000000000000000000000n</span>); <span class="hljs-comment">//false</span>
<span class="hljs-built_in">Number</span>.isInteger(<span class="hljs-string">""</span>); <span class="hljs-comment">//false</span>
</code></pre>
<h2 id="check-if-a-variable-is-a-floating-number">Check if a variable is a floating number</h2>
<p>It's a two step process:</p>
<ol>
<li>Check if the value is a numbe</li>
<li>Check if the value is not an integer</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-comment">// Solution</span>
<span class="hljs-keyword">const</span> isFloat = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isFloat</span>(<span class="hljs-params">val</span>)</span>{
  <span class="hljs-keyword">return</span> (<span class="hljs-keyword">typeof</span> val === <span class="hljs-string">'number'</span> &amp;&amp; !<span class="hljs-built_in">Number</span>.isInteger(val));
}

<span class="hljs-comment">// Test</span>
<span class="hljs-keyword">const</span> floatNumber = <span class="hljs-number">0.1</span>;
<span class="hljs-built_in">console</span>.log(isFloat(floatNumber)); <span class="hljs-comment">//true</span>
</code></pre>
<h2 id="check-if-a-variable-is-null">Check if a variable is <code>null</code></h2>
<p>Best way is to do a comparison.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> iamnull = <span class="hljs-literal">null</span>; 
<span class="hljs-keyword">const</span> zero = <span class="hljs-number">0</span>;

iamnull === <span class="hljs-literal">null</span>; <span class="hljs-comment">//true</span>
zero === <span class="hljs-literal">null</span>; <span class="hljs-comment">//false</span>
</code></pre>
<h2 id="check-if-a-variable-is-nan">Check if a variable is <code>NaN</code></h2>
<p>The <code>Number.isNaN</code> method returns true if the variable is an integer. </p>
<p>It's an improvement of the older <code>isNaN</code> function, since in that case you should also combine it with <code>typeof</code> check for number, otherwise something like <code>isNaN(undefined)</code> would also return true.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">Number</span>.isNaN(<span class="hljs-literal">NaN</span>); <span class="hljs-comment">//true</span>
<span class="hljs-built_in">Number</span>.isNaN(<span class="hljs-literal">undefined</span>); <span class="hljs-comment">//false</span>
</code></pre>
<h2 id="check-if-a-variable-is-a-regular-expression">Check if a variable is a regular expression</h2>
<p>To verify a variable is a regex simply check if it's an instance of the <code>RegExp</code> object.</p>
<pre><code class="lang-javascript">/I am a regex/ <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">RegExp</span> <span class="hljs-comment">//true</span>
<span class="hljs-literal">true</span> <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">RegExp</span> <span class="hljs-comment">//false</span>
</code></pre>
<h2 id="check-if-a-variable-is-a-date-object">Check if a variable is a <code>Date</code> object</h2>
<p>Similar to regex, for dates we can also check if the value is an instance of the <code>Date</code> object.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>() <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Date</span> <span class="hljs-comment">//true</span>
<span class="hljs-literal">true</span> <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Date</span> <span class="hljs-comment">//false</span>
</code></pre>
<h2 id="check-if-a-variable-is-a-custom-object">Check if a variable is a custom object</h2>
<p><code>typeof</code> will return <code>"object"</code> not just for objects but also for things like arrays and <code>null</code>. Your best option is to combine <code>typeof</code> with elimination. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> isObject = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isObject</span>(<span class="hljs-params">val</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="hljs-keyword">typeof</span> val === <span class="hljs-string">'object'</span> &amp;&amp;
    !<span class="hljs-built_in">Array</span>.isArray(val) &amp;&amp;
    val !== <span class="hljs-literal">null</span> &amp;&amp;
    val <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">RegExp</span> === <span class="hljs-literal">false</span> &amp;&amp;
    val <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Date</span> === <span class="hljs-literal">false</span>
  );
};
</code></pre>
<p>You can adjust this based on what you want to qualify as an object, however the objects I would like to validate are non-builtin JavaScript objects aka. objects defined by the developer.</p>
]]></content:encoded></item><item><title><![CDATA[Get the first and last moment of a day in Javascript]]></title><description><![CDATA[Here are 2 ready-to-use functions to get the first and last millisecond of a day using a few lines of vanilla JavaScript.
Get the first moment of a day
/**
 * Get first millisecond of a date
 * @param {Date} dateObj - JS Date object, default is curre...]]></description><link>https://danielcobo.com/get-the-first-and-last-moment-of-a-day-in-javascript</link><guid isPermaLink="true">https://danielcobo.com/get-the-first-and-last-moment-of-a-day-in-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[time]]></category><category><![CDATA[data]]></category><dc:creator><![CDATA[Daniel Cobo]]></dc:creator><pubDate>Mon, 10 May 2021 18:51:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1619648051286/93sB6LnPK.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Here are 2 ready-to-use functions to get the first and last millisecond of a day using a few lines of vanilla JavaScript.</p>
<h2 id="get-the-first-moment-of-a-day">Get the first moment of a day</h2>
<pre><code><span class="hljs-comment">/**
 * Get first millisecond of a date
 * <span class="hljs-doctag">@param <span class="hljs-type">{Date}</span> <span class="hljs-variable">dateObj</span></span> - JS Date object, default is current time
 * <span class="hljs-doctag">@returns </span>date object with time set to first millisecond of the day
 */</span>
<span class="hljs-keyword">const</span> beginningOfDay = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">beginningOfDay</span> (<span class="hljs-params">dateObj</span>) </span>{
  <span class="hljs-comment">//Get current date</span>
  <span class="hljs-keyword">const</span> now = dateObj || <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
  <span class="hljs-keyword">const</span> year = now.getFullYear();
  <span class="hljs-keyword">const</span> month = now.getMonth();
  <span class="hljs-keyword">const</span> day = now.getDate();

  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(year, month, day);
};
</code></pre><h3 id="1-set-a-default-value-to-the-date-argument">1. Set a default value to the date argument</h3>
<p>In case of no argument we set the date to current date and time. The below basically means if <code>dateObj</code> is defined set <code>now</code> to that, otherwise set it to a new <code>Date</code> object.</p>
<pre><code><span class="hljs-keyword">const</span> now = dateObj || <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
</code></pre><h3 id="2-extract-the-date-data">2. Extract the date data</h3>
<p><code>new Date()</code> returns the current date and time. Similarly, any <code>Date</code> object you input as an argument will probably also have a time. To get the start of a day we will need a fresh start. For that we first extract the year, month and day.</p>
<pre><code><span class="hljs-keyword">const</span> now = dateObj || <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
<span class="hljs-keyword">const</span> year = now.getFullYear();
<span class="hljs-keyword">const</span> month = now.getMonth();
<span class="hljs-keyword">const</span> day = now.getDate();
</code></pre><h3 id="3-we-generate-and-return-a-fresh-date">3. We generate and return a "fresh" date</h3>
<p>By generating a new <code>Date</code> using <code>year</code>, <code>month</code> and <code>day</code> as arguments you set the date of the JavaScript <code>Date</code> object. Because you didn't set the time, JS will set it to the first value which is 0 (0 hours, 0 minutes, 0 seconds, 0 milliseconds) . </p>
<pre><code><span class="hljs-keyword">return</span> <span class="hljs-built_in">new</span> <span class="hljs-type">Date</span>(year, month, day);
</code></pre><h2 id="get-the-last-moment-of-a-day">Get the last moment of a day</h2>
<pre><code><span class="hljs-comment">/**
 * Get last millisecond of a date
 * <span class="hljs-doctag">@param <span class="hljs-type">{Date}</span> <span class="hljs-variable">dateObj</span></span> - JS Date object, default is current time
 * <span class="hljs-doctag">@returns </span>date object with time set to last millisecond of the day
 */</span>
<span class="hljs-keyword">const</span> lastMomentOfDay = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">lastMomentOfDay</span>(<span class="hljs-params">dateObj</span>) </span>{
  <span class="hljs-comment">//Tomorrow = Current day + 1</span>
  <span class="hljs-keyword">let</span> tomorrow = beginningOfDay(dateObj);
  tomorrow.setDate(tomorrow.getDate() + <span class="hljs-number">1</span>);

  <span class="hljs-comment">//Tommorow - 1 milisecond = result</span>
  <span class="hljs-keyword">let</span> result = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
  result.setTime(tomorrow.getTime() - <span class="hljs-number">1</span>);
  <span class="hljs-keyword">return</span> result;
};
</code></pre><h3 id="1-get-the-first-moment-of-the-next-day">1. Get the first moment of the next day</h3>
<p>We leverage the function we wrote above (have a 🍪 for keeping your code <a target="_blank" href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a>).</p>
<pre><code>  <span class="hljs-built_in">let</span> tomorrow = beginningOfDay(dateObj);
  tomorrow.setDate(tomorrow.getDate() + 1);
</code></pre><h3 id="2-subtract-a-millisecond-from-tomorrow">2. Subtract a millisecond from tomorrow</h3>
<p>Remember, we got the first moment of tomorrow. If we subtract a millisecond from that, we will get the last millisecond the the day before, which is exactly what we are looking for.</p>
]]></content:encoded></item><item><title><![CDATA[Check if the user is from EU with JavaScript]]></title><description><![CDATA[Obviously your best guess is to ask the user. That being said, we generally want to avoid interrupting the user. Websites and apps are (or at least should be) about what the user's needs not ours. 
That being said, given the many legislation requirem...]]></description><link>https://danielcobo.com/check-if-the-user-is-from-eu-with-javascript</link><guid isPermaLink="true">https://danielcobo.com/check-if-the-user-is-from-eu-with-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[geolocation]]></category><category><![CDATA[cookies]]></category><category><![CDATA[APIs]]></category><dc:creator><![CDATA[Daniel Cobo]]></dc:creator><pubDate>Mon, 03 May 2021 21:13:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1619907494046/oTVFXIL4s.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Obviously your best guess is to ask the user. That being said, we generally want to avoid interrupting the user. Websites and apps are (or at least should be) about what the user's needs not ours. </p>
<p>That being said, given the many legislation requirements such as GDPR and cookie policy within the EU, it would be useful to know if we should display certain messaging. </p>
<h2 id="solution">Solution</h2>

<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/DanielCobo/pen/OJWeEEW">https://codepen.io/DanielCobo/pen/OJWeEEW</a></div>
<p>Let's break it down.</p>
<ol>
<li><p>Wrap everything in an <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/IIFE">IIFE</a> to avoid global namespace pollution:</p>
<pre><code class="lang-javascript">(<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
<span class="hljs-comment">//Our code goes here.. keep reading</span>
})();
</code></pre>
</li>
<li><p>Write a function to get the data from an IP lookup API. The function takes an optional <code>ip</code> parameter. If no value is given, no worries, the API will use the current IP that is making the call. In this case this will be the IP of whoever is visiting the page. The function will <code>fetch</code> the data, <code>await</code> for the reply and parse it. Parsing is minimal, <code>fetch</code> has methods to treat responses as <code>JSON</code> or text. we simply transform a text response into a <code>boolean</code> value - <code>true</code> if from EU and <code>false</code> if not. Simple right?  </p>
<pre><code class="lang-javascript"><span class="hljs-comment">/**
* Check if from EU based on IP
* <span class="hljs-doctag">@param <span class="hljs-type">{string}</span> </span>[ip] - IP, default is current
* <span class="hljs-doctag">@returns <span class="hljs-type">{string}</span> </span>- true/false if IP is from EU (https://ipapi.co/api/#complete-location)
*/</span>
<span class="hljs-keyword">const</span> fromEU = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fromEU</span>(<span class="hljs-params">ip</span>) </span>{
 <span class="hljs-keyword">let</span> url = <span class="hljs-string">'https://ipapi.co/'</span>;
 <span class="hljs-keyword">if</span> (ip) {
   url += ip + <span class="hljs-string">'/'</span>;
 }
 url += <span class="hljs-string">'in_eu/'</span>;
 <span class="hljs-keyword">return</span> fetch(url)
   .then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">response</span>) </span>{
     <span class="hljs-keyword">return</span> response.text();
   })
   .then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">txt</span>) </span>{
     <span class="hljs-keyword">if</span> (txt === <span class="hljs-string">'True'</span>) {
       <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
     } <span class="hljs-keyword">else</span> {
       <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
     }
   });
};
</code></pre>
</li>
<li><p>Remember, the function you just wrote is <code>async</code>, so <code>await</code> for the parsed reply (<code>true</code>/<code>false</code>). This would also be a great time to <strong>handle any errors</strong>, for this simple demo, let's just <code>log</code> to <code>console</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//Get data from IP lookup API</span>
<span class="hljs-keyword">const</span> isFromEU = <span class="hljs-keyword">await</span> fromEU().catch(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
 <span class="hljs-built_in">console</span>.log(err);
});
</code></pre>
</li>
<li><p>Do something with the data we just got. I admit, this is not particularly creative, but it'a a very direct way to show what this tutorial is about. Basically, if this IP is within the EU we want to checkmark and if not, then no checkmark. </p>
<pre><code class="lang-javascript"><span class="hljs-comment">//Un/check if from the EU</span>
<span class="hljs-keyword">let</span> checked = <span class="hljs-string">''</span>;
<span class="hljs-keyword">if</span> (isFromEU) {
 checked = <span class="hljs-string">'checked'</span>;
}
<span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">'body'</span>)[<span class="hljs-number">0</span>].innerHTML =
 <span class="hljs-string">'&lt;label&gt;&lt;input type="checkbox" name="fromEU" '</span> +
 checked +
 <span class="hljs-string">'&gt;I am from the EU&lt;/label&gt;'</span>;
</code></pre>
</li>
</ol>
<p>For the full code, check the <a class="post-section-overview" href="#solution">demo above</a>.  </p>
<p>Questions? Comments? Let me know here or <a target="_blank" href="https://twitter.com/danielcobocom">@danielcobocom</a>.</p>
<h2 id="api-disclaimer">API disclaimer</h2>
<p>Whenever you are using an API, like in this case it's an IP lookup service, be sure to check the terms, pricing, etc. APIs are great for adding function and often save time and money, but at the same time they can be points of failure, so always take some time to make sure the API is a good fit for your project.</p>
]]></content:encoded></item><item><title><![CDATA[Get user's preferred languages with JavaScript]]></title><description><![CDATA[Skip to solution
If you have different language settings in your website or application wouldn't it be great if you could automatically set the language the user prefers? Doing so may be easer than you think. All you have to do is use navigator.langu...]]></description><link>https://danielcobo.com/get-users-preferred-languages-with-javascript</link><guid isPermaLink="true">https://danielcobo.com/get-users-preferred-languages-with-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[languages]]></category><category><![CDATA[user experience]]></category><dc:creator><![CDATA[Daniel Cobo]]></dc:creator><pubDate>Mon, 26 Apr 2021 18:53:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1619463185887/a0RHm3p9k.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a class="post-section-overview" href="#solution">Skip to solution</a></p>
<p>If you have different language settings in your website or application wouldn't it be great if you could automatically set the language the user prefers? Doing so may be easer than you think. All you have to do is use <code>navigator.language</code> or better, <code>navigator.languages</code>.</p>
<h2 id="whats-the-difference-between-navigatorlanguage-and-navigatorlanguages">What's the difference between <code>navigator.language</code> and <code>navigator.languages</code>?</h2>
<p>They're basically the same, except <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/languages"><code>navigator.languages</code></a> is newer and should return the whole list of user languages by order of preference. This is great in case you don't have a translation in their top language, but perhaps you do for a fallback. </p>
<p>Speaking of fallbacks since <code>navigator.languages</code> implementation is experimental at the time of writing, it is wise to use <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/language"><code>navigator.language</code></a> as a fallback value. Just remember to wrap it in an <code>Array</code> for consistency.</p>
<h2 id="solution">Solution</h2>

<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/DanielCobo/pen/KKaJYEx">https://codepen.io/DanielCobo/pen/KKaJYEx</a></div>
<ol>
<li>Using <code>navigator.languages</code> (<code>[navigator.language]</code> as fallback) we get the preferred language list</li>
<li>The list is based on ISO 639-1 and may indicate country by the alpha 2 code of ISO 3166. You probably won't have separate localisations based on country. That is why we filter out unique language codes.</li>
<li>Lastly we convert the language codes to more human-friendly english names of the languages. </li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Get location by IP with JavaScript]]></title><description><![CDATA[Skip to solution.
Problem
Knowing your customer location can help you tailor their experience. Other times you may want to check for this information to compile statistics or comply with regulations. 
What's the best way to get location data?
One way...]]></description><link>https://danielcobo.com/get-location-by-ip-with-javascript</link><guid isPermaLink="true">https://danielcobo.com/get-location-by-ip-with-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[analytics]]></category><category><![CDATA[Geospatial]]></category><category><![CDATA[geolocation]]></category><category><![CDATA[APIs]]></category><dc:creator><![CDATA[Daniel Cobo]]></dc:creator><pubDate>Mon, 19 Apr 2021 19:28:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1618854738860/v7S9A2nGf.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a class="post-section-overview" href="#solution">Skip to solution</a>.</p>
<h2 id="problem">Problem</h2>
<p>Knowing your customer location can help you tailor their experience. Other times you may want to check for this information to compile statistics or comply with regulations. </p>
<h3 id="whats-the-best-way-to-get-location-data">What's the best way to get location data?</h3>
<p>One way to do it would be using the built-in HTML geolocation API. Another would be to use an IP lookup API. The best solution depends on your goals and needs.</p>
<blockquote>
<p>...most accurate location? Use the HTML geolocation API. </p>
</blockquote>
<p>Need the most accurate location? Use the  <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API">HTML geolocation API</a>. This will prompt the user for permission to use GPS (or whatever the device thinks is most accurate). </p>
<p>The prompt is great for privacy, but it can also be annoying to the user. This is especially true if they don't expect it. You should also keep in mind that modifying the design of the prompt is generally not an option. This makes sense, since security related UI for functions such as exact location should be uniform in regard to the device, not the app or website. </p>
<p>HTML geolocation is best when you need a very detailed location, but it can be too obtrusive when a general location would be enough. Unless you need GPS tracking, I would stay away from this option.</p>
<blockquote>
<p>...general location like city is enough? Use an IP lookup service.</p>
</blockquote>
<p>Don't want to bother the user and general location like city is enough? Use an IP lookup service. Another benefit of this approach is the <strong>extra information</strong>, depending on the provider, most commonly you will get things like currency, language, country, etc. </p>
<p>Beware, the <strong>accuracy of this approach will depend on the IP</strong>, so if the user is using a VPN, the location can be wildly off (you will get the location of the VPN). </p>
<p>If you are getting the location based on IP, it's a good idea to check with the user for confirmation or even better, use it only for default values only and let the user change any locale settings easily.</p>
<h2 id="solution">Solution</h2>

<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/DanielCobo/pen/oNBPQqx">https://codepen.io/DanielCobo/pen/oNBPQqx</a></div>
<p>First we write a function to grab the data from <a target="_blank" href="https://ipapi.co">ipapi.co</a>.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/**
 * Get data based on IP
 * <span class="hljs-doctag">@param <span class="hljs-type">{string}</span> </span>[ip] - IP, default is current
 * <span class="hljs-doctag">@returns <span class="hljs-type">{Object}</span> </span>- parsed API response
 */</span>
<span class="hljs-keyword">const</span> getLocale = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getLocale</span>(<span class="hljs-params">ip</span>) </span>{
  <span class="hljs-keyword">let</span> url = <span class="hljs-string">'https://ipapi.co/'</span>;
  <span class="hljs-keyword">if</span> (ip) {
    url += ip + <span class="hljs-string">'/'</span>;
  }
  url += <span class="hljs-string">'json/'</span>;
  <span class="hljs-keyword">return</span> fetch(url).then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">response</span>) </span>{
     <span class="hljs-keyword">return</span> response.json();
  });
};
</code></pre>
<p>The function takes an optional argument <code>ip</code>. This is useful in case we have an IP we would like to retrieve data for. The default <code>ip</code> value is the so-called public IP. This means that if the user has a VPN or something similar, it will be the VPN IP.</p>
<p>Secondly, we call <code>getLocale</code> and <a target="_blank" href="4"><code>await</code></a> for the response.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//Get locale data</span>
<span class="hljs-keyword">const</span> locale = <span class="hljs-keyword">await</span> getLocale().catch(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
  <span class="hljs-built_in">console</span>.log(err);
});
</code></pre>
<p>The <code>locale</code> object we just created holds all the location data and more. You can read the details in the <a target="_blank" href="https://ipapi.co/api/">API documentation</a>.</p>
<p>For us the most interesting properties are:</p>
<ul>
<li><code>locale.country_name</code> - name of the country</li>
<li><code>locale.country_code_iso3</code> - standardised <a target="_blank" href="https://www.iso.org/iso-3166-country-codes.html">ISO3 country code</a></li>
<li><code>locale.region</code> - in the testing I've done so far only useful for US, where it will give the state name</li>
<li><code>locale.city</code> - name of the city</li>
<li><code>locale.postal</code> - zip code</li>
</ul>
<h2 id="notes-on-using-the-api">Notes on using the API</h2>
<p>Here I used the API of <a target="_blank" href="https://ipapi.co">ipapi.co</a>, but there are <a target="_blank" href="https://stackoverflow.com/a/35123097">many other IP lookup providers</a> out there. I chose this particular one because:</p>
<ul>
<li>their API is super simple</li>
<li>they offer a good free solution </li>
<li>seems no signup is needed </li>
</ul>
<p>The above gives me confidence when I want to make a quick prototype or a small project. If I was to release an app to production it's probably better (and more fair) to get a paid plan. </p>
<p>At the very least be sure to double <strong>check the TOS of whatever API provider you are using</strong>. This way your app is less likely to suddenly lose a critical part of it's functionality due to failing APIs.</p>
]]></content:encoded></item><item><title><![CDATA[Use custom CSS for image input]]></title><description><![CDATA[Skip to solution.
Problem
HTML supports image input and on mobile it will even do all the heavy lifting for the Camera API for you, providing a nice native experience. Here's what it looks like:
https://codepen.io/DanielCobo/pen/vYgZKxm
But let's be ...]]></description><link>https://danielcobo.com/use-custom-css-for-image-input</link><guid isPermaLink="true">https://danielcobo.com/use-custom-css-for-image-input</guid><category><![CDATA[CSS]]></category><category><![CDATA[HTML]]></category><dc:creator><![CDATA[Daniel Cobo]]></dc:creator><pubDate>Mon, 12 Apr 2021 21:34:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1618663457324/sZR0TPvxi.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a href="#solution">Skip to solution</a>.</p>
<h2 id="problem">Problem</h2>
<p>HTML supports image input and on mobile it will even do all the heavy lifting for the Camera API for you, providing a nice native experience. Here's what it looks like:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/DanielCobo/pen/vYgZKxm">https://codepen.io/DanielCobo/pen/vYgZKxm</a></div>
<p>But let's be honest, the design sucks. Why?</p>
<ul>
<li>It's too basic and kinda ugly (yes, tastes differ, but really? you like this?) </li>
<li>It's wildly inconsistent across web browsers and operating systems. </li>
<li>You <strong>can't style it with CSS</strong>.</li>
</ul>
<p>I'd be OK if you could just add your own CSS, but it will only let you style the "box". The button, the message, etc. are all untouchable by CSS. It would have been so much better if they just let you manipulate those via  <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements">pseudo-elements</a> .</p>
<h2 id="solution">Solution</h2>

<p>The solution to the problem is done in 3 steps:</p>
<ol>
<li>Wrap the <code>&lt;input&gt;</code> in a <code>&lt;label&gt;</code> element</li>
<li>Hide the <code>&lt;input&gt;</code> element</li>
<li>Style the label as a button (Note: label text becomes the button text)</li>
</ol>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/DanielCobo/pen/gOgRLLa">https://codepen.io/DanielCobo/pen/gOgRLLa</a></div>
<h2 id="next-steps">Next steps</h2>
<p>The solution isn't perfect, but you can <strong>solve both drawbacks mentioned below with some JavaScript</strong>. If you have an interesting implementation or even better, if you came up with fixes that don't require JS, don't be shy and drop me a line.</p>
<h3 id="make-it-keyboard-accessible">Make it keyboard accessible</h3>
<p>Adding <code>tabindex="0"</code> to the label element will make it <em>tab-bable</em>, but pressing <code>ENTER</code>/<code>SPACE</code> doesn't activate it. What you could do is add a JS listener for the keypress. This defeats the purpose which is a <em>CSS only</em> solution. </p>
<p>However, if we were to use JS anyway we might as well be more semantic. Keep in mind clicking this control will activate the hidden input, so using a button would be much more semantic than a label element. </p>
<h3 id="add-visual-feedback-for-input-value">Add visual feedback for input value</h3>
<p>Often it is useful to see if/which image is in the input. The HTML solution is to provide you with a filename or text saying that the value is empty. </p>
<p>Again, we could solve this with some JS and listen to the value change. In this case I would also consider adding an image preview and a button to reset the input (set value to none). Using the built-in HTML input you can reset the input value too, but it's done in such an unintuitive way, doing a JS powered redesign is the way to go. </p>
]]></content:encoded></item></channel></rss>