{"componentChunkName":"component---src-templates-blog-post-js","path":"/blog/2009/03/09/all-in-one-cookie-function/","result":{"data":{"markdownRemark":{"html":"<p>Users stumbling across jQuery may notice the API’s designed so a method’s behaviour varies depending on the number and type of arguments passed in a call (have a look at the <a href=\"https://api.jquery.com/jQuery/\">jQuery method</a>!). In the right hands, this flexibility produces clean and elegant code without burdening the developer with 101 new method names to learn.</p>\n<p>Let’s do the same for cookies (source: <a href=\"https://hexmen.com/js/cookie.js\">cookie.js</a>).</p>\n<h3>Three into one does go</h3>\n<p>Googling for ’<a href=\"http://www.google.com/search?q=javascript+cookie+functions\">javascript cookie functions</a>’ brings back Peter-Paul Koch’s trio of functions from <a href=\"http://www.quirksmode.org/js/cookies.html\">QuirksMode</a>. The functions are named <code>setCookie</code>, <code>readCookie</code> and <code>eraseCookie</code>. Browsing through the next few search-results we see the same thing going by different names: <code>get</code>, <code>set</code> and <code>deleteCookie</code>; <code>add</code> &#x26; <code>remove</code>, <code>erase</code> &#x26; <code>delete</code>, <code>read</code>, <code>get</code> and <code>check</code> - all variations on a theme, all separating functionality into a trio of functions.</p>\n<p>Let’s look at the method signatures:</p>\n<ul>\n<li><code>createCookie(_name_, _value_, _days_)</code></li>\n<li><code>readCookie(_name_)</code></li>\n<li><code>eraseCookie(_name_)</code></li>\n</ul>\n<p>It’s pretty basic stuff.</p>\n<p>To merge the three functions into one, we have to differentiate between reading, writing and deleting a cookie by the number and value of arguments; I’ve chosen an implementation where deleting a cookie is achieved by setting it to <code>null</code>.</p>\n<p>Here’s some example usage:</p>\n<pre class=\"grvsc-container default-dark\" data-language=\"js\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk3\">// create a cookie:</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk11\">cookie</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;name&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;value&quot;</span><span class=\"mtk1\">);</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk3\">// read it:</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk11\">alert</span><span class=\"mtk1\">(</span><span class=\"mtk11\">cookie</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;name&quot;</span><span class=\"mtk1\">));</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk3\">// erase it:</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk11\">cookie</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;name&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk4\">null</span><span class=\"mtk1\">);</span></span></span></code></pre>\n<h3>Flexibility</h3>\n<p>All those cookie calls pass at least one parameter… but isn’t there something useful we can do with a plain parameterless <code>cookie()</code> call? Of course there is - let’s return an associative array of all cookie values!</p>\n<p>By default (without specifying an explicit expiry time) cookies survive until you restart the browser. It’s kinda mandatory to provide some way of specifying an <strong>expiry</strong> time.</p>\n<p>We’ll accept an <em>optional</em> third parameter specifying an expiry time in <em>days</em>:</p>\n<pre class=\"grvsc-container default-dark\" data-language=\"js\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk3\">// create cookie for 1 year</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk11\">cookie</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;theme&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;minimal&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk7\">365</span><span class=\"mtk1\">);</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk3\">// grab all cookies:</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">cookies</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">cookie</span><span class=\"mtk1\">();</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk11\">alert</span><span class=\"mtk1\">(</span><span class=\"mtk12\">cookies</span><span class=\"mtk1\">.</span><span class=\"mtk12\">theme</span><span class=\"mtk1\">);</span></span></span></code></pre>\n<p>Looking good so far. But there’s more.</p>\n<p>Like several of the cookie libraries, our function defaults to setting cookies on the top-level path ”/” - this is a more common requirement than the browsers default behaviour, which sets a cookie so it’s only used at or below the current page level (i.e. a cookie set while looking at “/products/Nintendo-DSi-Console_Black/978372” wouldn’t be available when looking at any other product.)</p>\n<p>To give developers flexibility I’ve made <strong>path</strong> another <em>optional</em> parameter - it could be used to share cookies between “/product/*” pages, but withhold them from any other area of a site.</p>\n<p>While we’re on the subject of sharing - what about cross-domain cookies? Cookies are naturally assigned to the domain the page is being viewed on, but sometimes we want to make sure a cookie’s available to all sub-domains too. <strong>domain</strong> is also an <em>optional</em> parameter.</p>\n<p>Having both <em>path</em> and <em>domain</em> as optional parameters could be confusing - after all, they’re both strings. Fortunately, we know paths begin with ”/” and domains don’t - and if you want to specify both you just stick to the right order: <em>path</em> then <em>domain</em>:</p>\n<pre class=\"grvsc-container default-dark\" data-language=\"js\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk3\">// share cookie between product pages:</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk11\">cookie</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;view-description&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;hidden&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;/products&quot;</span><span class=\"mtk1\">);</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk3\">// share cookie between domains:</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk11\">cookie</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;id&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;_&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;.ewelike.com&quot;</span><span class=\"mtk1\">);</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk3\">// save preferences cross-domain for 1 year:</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk11\">cookie</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;prefs&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;_&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk7\">365</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;/products&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;.ewelike.com&quot;</span><span class=\"mtk1\">);</span></span></span></code></pre>\n<p>Finally, there’s an optional ‘secure’ parameter. I’ve never used this myself, but it’s there if you want it. It’s handy if you’re storing sensitive information in cookies and you only want to allow the browser to transfer the cookie value when it’s request pages via https. The code will take any <em>truthy</em> value hanging off the end of the parameters (anything that’s not been interpreted as expiry date, path or domain.):</p>\n<pre class=\"grvsc-container default-dark\" data-language=\"js\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk3\">// set a secure cookie on the default path and domain</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk3\">// (expires when the browser closes)</span></span></span>\n<span class=\"grvsc-line\"><span class=\"grvsc-source\"><span class=\"mtk11\">cookie</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;name&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;value&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk4\">true</span><span class=\"mtk1\">);</span></span></span></code></pre>\n<p>Want the code? Grab it now… <a href=\"https://hexmen.com/js/cookie.js\">download cookie.js</a> (dual-licensed under MIT and GPL, exactly the same as jQuery)</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    position: relative;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n    line-height: 1.4;\n  }\n  \n  .grvsc-code {\n    display: table;\n  }\n  \n  .grvsc-line {\n    display: table-row;\n    box-sizing: border-box;\n    width: 100%;\n    position: relative;\n  }\n  \n  .grvsc-line > * {\n    position: relative;\n  }\n  \n  .grvsc-gutter-pad {\n    display: table-cell;\n    padding-left: 0.75rem;\n    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);\n  }\n  \n  .grvsc-gutter {\n    display: table-cell;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    user-select: none;\n  }\n  \n  .grvsc-gutter::before {\n    content: attr(data-content);\n  }\n  \n  .grvsc-source {\n    display: table-cell;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-source:empty::after {\n    content: ' ';\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    user-select: none;\n  }\n  \n  .grvsc-gutter + .grvsc-source {\n    padding-left: 0.75rem;\n    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);\n  }\n  \n  /* Line transformer styles */\n  \n  .grvsc-has-line-highlighting > .grvsc-code > .grvsc-line::before {\n    content: ' ';\n    position: absolute;\n    width: 100%;\n  }\n  \n  .grvsc-line-diff-add::before {\n    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));\n  }\n  \n  .grvsc-line-diff-del::before {\n    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));\n  }\n  \n  .grvsc-line-number {\n    padding: 0 2px;\n    text-align: right;\n    opacity: 0.7;\n  }\n  \n  .default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .default-dark .mtk3 { color: #6A9955; }\n  .default-dark .mtk11 { color: #DCDCAA; }\n  .default-dark .mtk1 { color: #D4D4D4; }\n  .default-dark .mtk8 { color: #CE9178; }\n  .default-dark .mtk4 { color: #569CD6; }\n  .default-dark .mtk7 { color: #B5CEA8; }\n  .default-dark .mtk12 { color: #9CDCFE; }\n  .default-dark .grvsc-line-highlighted::before {\n    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));\n  }\n</style>","timeToRead":3,"frontmatter":{"title":"All-in-one cookie function","blurb":"Presenting a single overloaded function to get, set or delete cookies","date":"2009-03-09T11:18:06.000Z","modified":"2011-01-03T17:20:13.000Z"}}},"pageContext":{"slug":"/blog/2009/03/09/all-in-one-cookie-function/","next":{"fields":{"slug":"/blog/2009/12/03/javascript-date-to-time/"},"frontmatter":{"title":"JavaScript Date to Time"}},"previous":{"fields":{"slug":"/blog/2009/02/23/macbook-pro-not-so-bad/"},"frontmatter":{"title":"The MacBook Pro’s not so bad..."}}}},"staticQueryHashes":["1192980692"]}