{"id":524,"date":"2018-05-16T13:30:06","date_gmt":"2018-05-16T13:30:06","guid":{"rendered":"https:\/\/www.audero.it\/blog\/?p=524"},"modified":"2018-05-16T13:30:06","modified_gmt":"2018-05-16T13:30:06","slug":"event-delegation-in-javascript","status":"publish","type":"post","link":"https:\/\/www.audero.it\/blog\/2018\/05\/16\/event-delegation-in-javascript\/","title":{"rendered":"Event delegation in JavaScript"},"content":{"rendered":"<p>One of the most common tasks a web developer deals with is to add <a href=\"https:\/\/www.audero.it\/blog\/2018\/04\/18\/in-depth-guide-event-listeners\/\">event listeners<\/a> to the elements of a page. Event listeners are employed to perform one or more actions when a given event occurs on one or more elements.<\/p>\n<p>For example, by using an event listener we could display a dialog when a button is clicked by a user. In this case, the developer is running a single action (showing the dialog) when a <code>click<\/code> event occurs on one element (the button). Another example is a pagination widget. The latter is made of many links that lead the user to a given page when clicked. Here, the action is performed on many elements. The final example I want to mention is to use an event listener with elements that don&#8217;t yet exist in the page but will. This happens when injecting elements in the web page after the page is fully loaded, for example after an Ajax request is performed.<\/p>\n<p>In this article, I&#8217;ll discuss how you, as a web developer, can optimize the addition of event listeners in all these situations by employing a technique called <strong>event delegation<\/strong>.<br \/>\n<!--more--><\/p>\n<h2>What problems event delegation solve?<\/h2>\n<p>Before we delve into what <em>event delegation<\/em> is, it&#8217;s important to understand why we might need it in first place.<\/p>\n<p>Imagine that we&#8217;re creating a website with a search box. The results of a search are displayed in different chunks (pages) and the user should be able to navigate them. For this reason, we could create a pagination widget (or component). To avoid a full reload of the web page when a user selects another page from the widget, for example the second or the third, we want to employ <a href=\"https:\/\/web.archive.org\/web\/20080702075113\/http:\/\/www.adaptivepath.com\/ideas\/essays\/archives\/000385.php\" target=\"_blank\">Ajax<\/a> to fetch the new results. Then, we&#8217;ll show them. We also want to follow the principles of <a href=\"https:\/\/www.smashingmagazine.com\/2009\/04\/progressive-enhancement-what-it-is-and-how-to-use-it\/\" target=\"_blank\">progressive enhancement<\/a>. By doing so, we ensure that a user will still be able to navigate the results if JavaScript is disabled or fails for any reason, and enhance the user experience if the JavaScript code is correctly loaded and executed. To avoid cluttering the interface, the pagination widget will always show up to five pages, even if there are more available.<\/p>\n<p>The HTML code of the pagination widget could be as follows:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;ol class=&quot;pagination&quot;&gt;\r\n   &lt;li class=&quot;active&quot;&gt;\r\n      &lt;a href=&quot;page\/1&quot;&gt;1&lt;\/a&gt;\r\n   &lt;\/li&gt;\r\n   &lt;li&gt;\r\n      &lt;a href=&quot;page\/2&quot;&gt;2&lt;\/a&gt;\r\n   &lt;\/li&gt;\r\n   &lt;li&gt;\r\n      &lt;a href=&quot;page\/3&quot;&gt;3&lt;\/a&gt;\r\n   &lt;\/li&gt;\r\n   &lt;li&gt;\r\n      &lt;a href=&quot;page\/4&quot;&gt;4&lt;\/a&gt;\r\n   &lt;\/li&gt;\r\n   &lt;li&gt;\r\n      &lt;a href=&quot;page\/5&quot;&gt;5&lt;\/a&gt;\r\n   &lt;\/li&gt;\r\n&lt;\/ol&gt;\r\n<\/pre>\n<p>As you can see from the above code, the widget is made of an ordered list containing five links. Each of these links leads to a different results page. The class names used have no special meaning. They are there so that I can used later on to retrieve the elements.<\/p>\n<p>To avoid a full reload of the web page, when a results page is selected, we need to add an event listener for the <code>click<\/code> event on all the anchor elements (<code>a<\/code>) of the widget. Inside the listener we have to prevent the default action.<\/p>\n<p><small>The default action the browser performs when an <code>a<\/code> element is clicked is to load the resource found at the URL specified, causing a full reload of the page.<\/small><\/p>\n<p>Once we&#8217;ve stopped the default action, we have to send the Ajax request to the URL specified by the anchor to fetch more results. Then, we need to display the new results. In addition, as the user navigates through the pages, we want to check if there are more page results available. If this is the case, we have to update the pagination widget accordingly so that the user can navigate more than just the initial five pages. Finally, we want to keep the maximum number of links displayed to five. This means that at every update some anchors will be added to the widget and some will be removed.<\/p>\n<p>A possible implementation, which omits most of the code to focus on the matter at hand (event delegation), is shown below:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction onClick(event) {\r\n   \/\/ Prevent the default action\r\n   event.preventDefault();\r\n\r\n   \/\/ Store the link of the clicked anchor\r\n   const url = event.target.href;\r\n\r\n   \/\/ Update the results by sending an Ajax request\r\n   \/\/ to the URL specified in the &quot;url&quot; variable\r\n\r\n   \/\/ Update the anchors in the pagination widget\r\n   \/\/ and remove the event listener on the deleted anchors\r\n\r\n   console.log('Fetching results at ' + url);\r\n}\r\n\r\nconst anchors = document.querySelectorAll('.pagination a');\r\n\r\nfor (let i = 0; i &lt; anchors.length; i++) {\r\n   anchors&#x5B;i].addEventListener('click', onClick);\r\n}\r\n<\/pre>\n<p>The approach shown in the code above, also <a href=\"https:\/\/jsbin.com\/natoci\/edit?js,console,output\" target=\"_blank\">available on JSBin<\/a>, has a few problems.<\/p>\n<p>The first problem is that the code only adds the event listener on anchors that are already in the page. It doesn&#8217;t take into account those that don&#8217;t exist yet but will because of the updates to the pagination widget. The consequence is that if the user clicks on any of the new added anchors, a full reload of the page will occur. To solve this problem, we could add the event listener right after a new anchor is created. But this solution introduces a new issue, explained below.<\/p>\n<p>JavaScript is a single-threaded language, thus it can&#8217;t execute more than one operation at a time. This means that while some code is executed no other operations can be performed. Any new operation is placed into a queue, including those performed because of the interaction of the user with the page. So, to improve the performance of the web page, we should avoid running an operation every time the widget is updated.<\/p>\n<p>Another problem is that the proposed approach wastes a lot of memory. It adds an event listener to every <code>a<\/code> element added to the widget, even if the operation to execute is the same.<\/p>\n<p>The solution to all these problems is to employ <em>event delegation<\/em>.<\/p>\n<h2>What is event delegation?<\/h2>\n<p><dfn><em>Event delegation<\/em><\/dfn> is a technique that consists of adding an event listener to an ancestor of the element(s) on which the event of interest will be fired, instead of the element(s) itself. In the previous example, we would add an event listener to an ancestor of the anchor elements, for example the list itself.<\/p>\n<p>Event delegation takes advantage of the propagation of events in the <abbr title=\"Document Object Model\">DOM<\/abbr>. In most cases, the event listener is executed during the <em>bubble phase<\/em>, but we can execute a listener during the <em>capturing phase<\/em> as well.<\/p>\n<p><small>If you want to know more about the event dispatch mechanism of the event model, you can read the section <cite><a href=\"https:\/\/www.w3.org\/TR\/uievents\/#event-flow\" target=\"_blank\">Event dispatch and DOM event flow<\/a><\/cite> of the <cite>W3C UI Events Specification<\/cite>.<\/small><\/p>\n<figure>\n <img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"529\" data-permalink=\"https:\/\/www.audero.it\/blog\/2018\/05\/16\/event-delegation-in-javascript\/dom-event-propagation\/\" data-orig-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/06\/dom-event-propagation.jpg\" data-orig-size=\"520,560\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/06\/dom-event-propagation.jpg\" src=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/06\/dom-event-propagation.jpg\" alt=\"DOM event propagation\" width=\"520\" height=\"560\" class=\"aligncenter size-full wp-image-529\" srcset=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/06\/dom-event-propagation.jpg 520w, https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/06\/dom-event-propagation-279x300.jpg 279w\" sizes=\"auto, (max-width: 520px) 100vw, 520px\" \/><figcaption>Graphical representation of an event dispatched in a DOM tree<\/figcaption><\/figure>\n<p>Now that you know what event delegation is, let&#8217;s modify the previous example to see this technique in action.<\/p>\n<h3>Event delegation in action<\/h3>\n<p>Before we start updating the code of our example, we have to find an element that is ancestor of all the elements we are interested in (the anchors). As mentined before, all the anchors are contained in the ordered list, so the latter is a good candidate. Now that we have found the right element, the first change is to add the event listener on the ordered list instead of all the anchors.<\/p>\n<p>An event listener added to an element instead of its descendants to employ event delegation is called <dfn>delegated event listener<\/dfn> or <dfn>delegated listener<\/dfn>.<\/p>\n<p>The second change consist in the deletion of the <code>for<\/code> statement. In the first snippet we used it to add the event listener on all the anchors, but in this updated version we are only adding one event listener. So, there is nothing to loop over.<\/p>\n<p>The last change required needs a bit more thinking and discussion. In the first version of the code we were attaching the listener on the elements (the anchors) where the event of interest, the <code>click<\/code> event, is triggered. Therefore, every time the event occurs, all the operations defined in the event listener should be executed. In the improved version we&#8217;re developing, we&#8217;re adding a listener on an ancestor of the anchors and relying on event propagation. But because the chosen ancestor might be the ancestor of other elements we aren&#8217;t interested in, we have to prevent that events fired on these elements are ignored by our event listener.<\/p>\n<p>In our pagination widget, if the <code>click<\/code> event is generated on a list item or on the ordered list itself, we don&#8217;t want to execute the event listener. So, we need a way to distinguish between  the <code>click<\/code> events of interest and those to ignore. The widget we&#8217;re analyzing is pretty simple, so it&#8217;ll be enough to check the name of the element on which the event is fired. In particular, we need to check that the name of the element is <code>A<\/code>. To do that, we can check the <code>nodeName<\/code> property of the element referenced by <code>event.target<\/code>.<\/p>\n<figure>\n <img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"590\" data-permalink=\"https:\/\/www.audero.it\/blog\/2018\/05\/16\/event-delegation-in-javascript\/event-delegation-2\/\" data-orig-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/08\/event-delegation.png\" data-orig-size=\"733,424\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"event delegation\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/08\/event-delegation.png\" src=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/08\/event-delegation.png\" alt=\"event delegation\" width=\"733\" height=\"424\" class=\"aligncenter size-full wp-image-590\" srcset=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/08\/event-delegation.png 733w, https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/08\/event-delegation-300x174.png 300w\" sizes=\"auto, (max-width: 733px) 100vw, 733px\" \/><figcaption>Graphical representation of event delegation<\/figcaption><\/figure>\n<p>The updated version of our code that employs event delegation is reported below and also <a href=\"https:\/\/jsbin.com\/yamode\/edit?js,console,output\" target=\"_blank\">available on JSBin<\/a>.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction onClick(event) {\r\n   \/\/ If the event is not triggered on one of the anchors,\r\n   \/\/ there is nothing we want to do\r\n   if (event.target.nodeName !== 'A') {\r\n      return;\r\n   }\r\n\r\n   \/\/ Prevent the default action\r\n   event.preventDefault();\r\n\r\n   \/\/ Store the link of the clicked anchor\r\n   const url = event.target.href;\r\n\r\n   \/\/ Update the results by sending an Ajax request\r\n   \/\/ to the URL specified in the &quot;url&quot; variable\r\n\r\n   \/\/ Update the anchors in the pagination widget\r\n\r\n   console.log('Fetching results at ' + url);\r\n}\r\n\r\nconst pagination = document.querySelector('.pagination');\r\n\r\npagination.addEventListener('click', onClick);\r\n<\/pre>\n<p>In the presented example, the choice of the ancestor to use was simple but this isn&#8217;t always the case. In the next section, I&#8217;ll discuss some rules of thumb for choosing the best ancestor element to use when employing event delegation.<\/p>\n<h3>What makes a good candidate for event delegation?<\/h3>\n<p>In the final version of our code, we have used the ordered list to attach the event listener used to fetch the new results, but its parent or one of its ancestors would have been possible candidates too. For example, we could have chosen the <code>body<\/code> or the <code>html<\/code> element as the ancestor to add the event listener.<\/p>\n<p>Because the <code>html<\/code> element contains all the elements of the page, it&#8217;s always a possible candidate. Based on this consideration, you might think to always use it and avoid any additional thinking. But attaching many delegated listeners to the root or an element near the root of the <abbr title=\"Document Object Model\">DOM<\/abbr> can degrade the performance of a web page. In such cases, every time the event of interest is fired on a descendant of the element, the event listener is executed. We could differentiate between the events as we&#8217;ve done in our example, but why executing the listener when it isn&#8217;t necessary?<\/p>\n<p>A good practice is to attach the event listener to an element that is ancestor of all the elements of interest that is as close as possible to them in the <abbr title=\"Document Object Model\">DOM<\/abbr> tree. This ensures the best performance while not having to add an event listener to each element we&#8217;re targeting.<\/p>\n<h2>Conclusions<\/h2>\n<p>In this article I&#8217;ve covered a technique called event delegation. The latter consists of adding an event listener to an ancestor of the element(s) on which the event of interest will be fired and takes advantage of the propagation of events in the <abbr title=\"Document Object Model\">DOM<\/abbr>.<\/p>\n<p>Event delegation allows a web developer to save memory when managing events and it&#8217;s especially convenient when working with web pages where elements are dynamically added and deleted. In your career you&#8217;ll find a lot of situations where event delegation is the right approach. So many, in fact, that you&#8217;ll ask yourself how you even worked without it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the most common tasks a web developer deals with is to add <a href=\"https:\/\/www.w3.org\/TR\/DOM-Level-2-Events\/events.html#Events-EventListener\" target=\"_blank\">event listeners<\/a> to the elements of a page. Event listeners are employed to perform one or more actions when a given event occurs on one or more elements.<\/p>\n<p>For example, by using an event listener we could display a dialog when a button is clicked by a user. In this case, the developer is running a single action (showing the dialog) when a <code>click<\/code> event occurs on one element (the button). Another example is a pagination widget. The latter is made of many links that have to lead the user to a given page when clicked. Here, the developer is performing the same, single action on many elements. The final example I want to mention is to use an event listener with elements that don&#8217;t yet exist in the page but will. This happens when injecting elements in the web page after an Ajax request is performed.<\/p>\n<p>In this article, I&#8217;ll discuss how you, as a web developer, can optimize the addition of event listeners in all these situations by employing a technique called <code>event delegation<\/code>.<\/p>\n","protected":false},"author":1,"featured_media":592,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[3],"tags":[19,59,65,58,46,23,11],"class_list":["post-524","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-javascript","tag-browser","tag-dom","tag-dom-events","tag-event-delegation","tag-javascript","tag-performance","tag-web"],"jetpack_featured_media_url":"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/08\/event-delegation-1.png","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p9Or4e-8s","jetpack-related-posts":[{"id":539,"url":"https:\/\/www.audero.it\/blog\/2018\/04\/18\/in-depth-guide-event-listeners\/","url_meta":{"origin":524,"position":0},"title":"An in-depth guide to event listeners","author":"Aurelio De Rosa","date":"April 18, 2018","format":false,"excerpt":"When creating interactive web pages, developers often need to execute some actions when a given event occurs. Changing the image of a carousel when a user clicks on one of its arrows, showing a tooltip when a word is hovered, or validating a field when a user moves the focus\u2026","rel":"","context":"In &quot;JavaScript&quot;","block_context":{"text":"JavaScript","link":"https:\/\/www.audero.it\/blog\/category\/javascript\/"},"img":{"alt_text":"Removing an event listener","src":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2018\/04\/event-listeners-removing-event-listener.gif?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2018\/04\/event-listeners-removing-event-listener.gif?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2018\/04\/event-listeners-removing-event-listener.gif?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2018\/04\/event-listeners-removing-event-listener.gif?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":832,"url":"https:\/\/www.audero.it\/blog\/2018\/07\/20\/5-javascript-interview-questions-a-mid-level-developer-should-be-able-to-answer\/","url_meta":{"origin":524,"position":1},"title":"5 JavaScript interview questions a mid-level developer should be able to answer","author":"Aurelio De Rosa","date":"July 20, 2018","format":false,"excerpt":"According to the results of the 2018's StackOverflow survey, JavaScript is the most popular technology. The amount of job offers for JavaScript developers is constantly increasing and with more companies adopting JavaScript as their main language, it's easy to find good ones. But before you are hired by a company,\u2026","rel":"","context":"In &quot;JavaScript&quot;","block_context":{"text":"JavaScript","link":"https:\/\/www.audero.it\/blog\/category\/javascript\/"},"img":{"alt_text":"job interview panel","src":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/06\/job-interview-panel.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/06\/job-interview-panel.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/06\/job-interview-panel.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/06\/job-interview-panel.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/06\/job-interview-panel.jpg?resize=1050%2C600&ssl=1 3x"},"classes":[]},{"id":148,"url":"https:\/\/www.audero.it\/blog\/2013\/09\/05\/how-to-create-custom-filters-in-jquery\/","url_meta":{"origin":524,"position":2},"title":"How to Create Custom Filters in jQuery","author":"Aurelio De Rosa","date":"September 5, 2013","format":false,"excerpt":"In some cases you may need a shortcut to collect elements for which jQuery doesn't provide a specific filter. This is exactly where custom filters come into play. In this article, extracted from my book Instant jQuery Selectors, you'll learn how to build a custom filter in jQuery. Please note\u2026","rel":"","context":"In &quot;JavaScript&quot;","block_context":{"text":"JavaScript","link":"https:\/\/www.audero.it\/blog\/category\/javascript\/"},"img":{"alt_text":"jquery logo","src":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2013\/09\/jquery-logo.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2013\/09\/jquery-logo.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2013\/09\/jquery-logo.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2013\/09\/jquery-logo.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2013\/09\/jquery-logo.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2013\/09\/jquery-logo.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":329,"url":"https:\/\/www.audero.it\/blog\/2014\/09\/19\/resources-beginner-front-end-developers\/","url_meta":{"origin":524,"position":3},"title":"Resources for Beginner Front-end Developers","author":"Aurelio De Rosa","date":"September 19, 2014","format":false,"excerpt":"Few weeks ago I received an email from a developer asking me for suggestions on how to delve into the front-end world. After having replied to this email, I thought that it'd have been nice to share the same suggestions on my blog. That's exactly what you'll find in this\u2026","rel":"","context":"In &quot;Discussions &amp; Opinions&quot;","block_context":{"text":"Discussions &amp; Opinions","link":"https:\/\/www.audero.it\/blog\/category\/discussions-opinions\/"},"img":{"alt_text":"html5 css3 javascript logos","src":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2014\/09\/front-end-stack.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2014\/09\/front-end-stack.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2014\/09\/front-end-stack.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2014\/09\/front-end-stack.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2014\/09\/front-end-stack.png?resize=1050%2C600&ssl=1 3x"},"classes":[]},{"id":339,"url":"https:\/\/www.audero.it\/blog\/2014\/10\/18\/state-web-notifications-api\/","url_meta":{"origin":524,"position":4},"title":"The State of the Web Notifications API","author":"Aurelio De Rosa","date":"October 18, 2014","format":false,"excerpt":"Today I was reviewing my HTML5 API demos repository to keep its information updated and relevant. In the last two weeks Google has released\u00a0Chrome 38, Opera has released Opera 25, and Mozilla has released Firefox 33.\u00a0Every time a new version of a browser is available, it may\u00a0introduce support for new\u2026","rel":"","context":"In &quot;JavaScript&quot;","block_context":{"text":"JavaScript","link":"https:\/\/www.audero.it\/blog\/category\/javascript\/"},"img":{"alt_text":"push notifications","src":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2014\/10\/push-notifications.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2014\/10\/push-notifications.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2014\/10\/push-notifications.jpg?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":170,"url":"https:\/\/www.audero.it\/blog\/2013\/09\/16\/15-tips-to-improve-your-jquery-selectors\/","url_meta":{"origin":524,"position":5},"title":"15 Tips to Improve Your jQuery Selectors","author":"Aurelio De Rosa","date":"September 16, 2013","format":false,"excerpt":"Who don't know what jQuery is and how it can help in developing a web project. Based on the latest statistics, jQuery is used on ~60% of the Quantcast Top 100k websites. We use it constantly and sometimes we tend to think it's almost magic, that jQuery is capable to\u2026","rel":"","context":"In &quot;JavaScript&quot;","block_context":{"text":"JavaScript","link":"https:\/\/www.audero.it\/blog\/category\/javascript\/"},"img":{"alt_text":"jquery logo","src":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2013\/09\/jquery-logo.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2013\/09\/jquery-logo.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2013\/09\/jquery-logo.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2013\/09\/jquery-logo.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2013\/09\/jquery-logo.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2013\/09\/jquery-logo.png?resize=1400%2C800&ssl=1 4x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/posts\/524","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/comments?post=524"}],"version-history":[{"count":25,"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/posts\/524\/revisions"}],"predecessor-version":[{"id":829,"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/posts\/524\/revisions\/829"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/media\/592"}],"wp:attachment":[{"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/media?parent=524"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/categories?post=524"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/tags?post=524"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}