{"id":191783,"date":"2014-12-29T03:38:12","date_gmt":"2014-12-29T10:38:12","guid":{"rendered":"http:\/\/css-tricks.com\/?page_id=191783"},"modified":"2021-08-04T08:46:49","modified_gmt":"2021-08-04T15:46:49","slug":"deep-getset-maps","status":"publish","type":"page","link":"https:\/\/css-tricks.com\/snippets\/sass\/deep-getset-maps\/","title":{"rendered":"Deep Get\/Set in Maps"},"content":{"rendered":"\n

When working on complex Sass architectures, it is not uncommon to use Sass maps to maintain configuration and options. From time to time, you’ll see maps within maps (possibly on several levels) like this one from o-grid<\/a>:<\/p>\n\n\n\n

$o-grid-default-config: (\n    columns: 12,\n    gutter: 10px,\n    min-width: 240px,\n    max-width: 1330px,\n    layouts: (\n        S:  370px,  \/\/ \u226520px columns\n        M:  610px,  \/\/ \u226540px columns\n        L:  850px,  \/\/ \u226560px columns\n        XL: 1090px  \/\/ \u226580px columns\n    ),\n    fluid: true,\n    debug: false,\n    fixed-layout: M,\n    enhanced-experience: true\n);<\/code><\/pre>\n\n\n\n

The problem with such maps is that it is not easy to get and set values from the nested tree. This is definitely something you want to hide within functions in order to avoid having to do it manually every time.<\/p>\n\n\n

Deep get<\/h3>\n\n\n

Actually, building a function to fetch deeply nested values from a map is very easy.<\/p>\n\n\n\n

\/\/\/ Map deep get\n\/\/\/ @author Kitty Giraudel\n\/\/\/ @access public\n\/\/\/ @param {Map} $map - Map\n\/\/\/ @param {Arglist} $keys - Key chain\n\/\/\/ @return {*} - Desired value\n@function map-deep-get($map, $keys...) {\n    @each $key in $keys {\n        $map: map-get($map, $key);\n    }\n    @return $map;\n}<\/code><\/pre>\n\n\n\n

For instance, if we want to get the value associated to the M<\/code> layout from our configuration map, it is as easy as:<\/p>\n\n\n\n

$m-breakpoint: map-deep-get($o-grid-default-config, \"layouts\", \"M\");\n\/\/ 610px<\/code><\/pre>\n\n\n\n

Note that quotes around strings are optional. We only add them for readability concerns.<\/p>\n\n\n

Deep set<\/h3>\n\n\n

On the other hand, building a function to set a deeply nested key can be very tedious.<\/p>\n\n\n\n

\/\/\/ Deep set function to set a value in nested maps\n\/\/\/ @author Kitty Giraudel\n\/\/\/ @access public\n\/\/\/ @param {Map} $map - Map\n\/\/\/ @param {List} $keys -  Key chaine\n\/\/\/ @param {*} $value - Value to assign\n\/\/\/ @return {Map}\n@function map-deep-set($map, $keys, $value) {\n  $maps: ($map,);\n  $result: null;\n  \n  \/\/ If the last key is a map already\n  \/\/ Warn the user we will be overriding it with $value\n  @if type-of(nth($keys, -1)) == \"map\" {\n    @warn \"The last key you specified is a map; it will be overrided with `#{$value}`.\";\n  }\n  \n  \/\/ If $keys is a single key\n  \/\/ Just merge and return\n  @if length($keys) == 1 {\n    @return map-merge($map, ($keys: $value));\n  }\n  \n  \/\/ Loop from the first to the second to last key from $keys\n  \/\/ Store the associated map to this key in the $maps list\n  \/\/ If the key doesn't exist, throw an error\n  @for $i from 1 through length($keys) - 1 {\n    $current-key: nth($keys, $i);\n    $current-map: nth($maps, -1);\n    $current-get: map-get($current-map, $current-key);\n    @if $current-get == null {\n      @error \"Key `#{$key}` doesn't exist at current level in map.\";\n    }\n    $maps: append($maps, $current-get);\n  }\n  \n  \/\/ Loop from the last map to the first one\n  \/\/ Merge it with the previous one\n  @for $i from length($maps) through 1 {\n    $current-map: nth($maps, $i);\n    $current-key: nth($keys, $i);\n    $current-val: if($i == length($maps), $value, $result);\n    $result: map-merge($current-map, ($current-key: $current-val));\n  }\n  \n  \/\/ Return result\n  @return $result;\n}<\/code><\/pre>\n\n\n\n

Now if we want to update the value associated to the M<\/code> layout from our configuration map, we can do:<\/p>\n\n\n\n

$o-grid-default-config: map-deep-set($o-grid-default-config, \"layouts\" \"M\", 650px);<\/code><\/pre>\n\n\n

Extra resources<\/h3>\n\n\n

The above function is not the only solution to this problem.<\/p>\n\n\n\n

The Sassy-Maps<\/a> library also provides map-deep-set<\/code><\/a> and map-deep-get<\/code><\/a> functions. Along the same lines, Kitty Giraudel<\/a> also has written a jQuery-style extend<\/code> function<\/a> to make the built-in map-merge<\/code> recursive and able to merge more than 2 maps at once.<\/p>\n","protected":false},"excerpt":{"rendered":"

When working on complex Sass architectures, it is not uncommon to use Sass maps to maintain configuration and options. From time to time, you’ll see maps within maps (possibly on several levels) like this one from o-grid: The problem with such maps is that it is not easy to get and set values from the […]<\/p>\n","protected":false},"author":40123,"featured_media":0,"parent":191187,"menu_order":0,"comment_status":"open","ping_status":"closed","template":"page-snippet.php","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"footnotes":""},"tags":[],"acf":[],"jetpack-related-posts":[{"id":249595,"url":"https:\/\/css-tricks.com\/snippets\/sass\/use-sass-variable-selector\/","url_meta":{"origin":191783,"position":0},"title":"Use a Sass Variable for a Selector","date":"January 2, 2017","format":false,"excerpt":"Say you need to use a certain selector in multiple places in your code. It's not tremendously common, to be sure, but stuff happens. Repeated code is typically an opportunity for abstraction. Abstracting values in Sass is easy, but selectors is slightly trickier. One way to do it is to\u2026","rel":"","context":"In \"Sass\"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":165577,"url":"https:\/\/css-tricks.com\/video-screencasts\/132-quick-useful-case-sass-math-mixins\/","url_meta":{"origin":191783,"position":1},"title":"#132: A Quick Useful Case for Sass Math and Mixins","date":"March 13, 2014","format":false,"excerpt":"I had a little design situation come up where I was making a fluid grid of boxes with floats. I wanted to specify how many boxes across a row was very easily, and have them flush against both edges of the container. Not too difficult, as we know from not\u2026","rel":"","context":"With 31 comments","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":192767,"url":"https:\/\/css-tricks.com\/snippets\/sass\/fix-number-n-digits\/","url_meta":{"origin":191783,"position":2},"title":"Fix a Number to N Digits","date":"January 9, 2015","format":false,"excerpt":"When dealing with numbers in JavaScript or any other programming language, there is a way to truncate a number after n digits. Unfortunately, there is no such function in Sass. Still, rounding and precision issues do happen when dealing with percentage based grid systems for instance. Here is a Sass\u2026","rel":"","context":"Similar post","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":191206,"url":"https:\/\/css-tricks.com\/snippets\/sass\/mixin-prefix-properties\/","url_meta":{"origin":191783,"position":3},"title":"Mixin to Prefix Properties","date":"December 19, 2014","format":false,"excerpt":"In case you're interested in handling your own CSS vendor prefixing (rather than, say, Autoprefixer or Compass), here is a mixin to help with that. Rather than just appending every known prefix to everything, you pass it the prefixes you want to use, so you have more fine grained control\u2026","rel":"","context":"With 2 comments","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1586,"url":"https:\/\/css-tricks.com\/video-screencasts\/34-integrating-and-customizing-google-maps\/","url_meta":{"origin":191783,"position":4},"title":"#34: Integrating and Customizing Google Maps","date":"January 4, 2009","format":false,"excerpt":"Google maps, with all the dragging and zooming and satellite view and all, is my mapping service of choice. Google offers an free API for their maps so you can integrate them right onto your site. Set you own default location, zoom level, widgetry. Even add your own markers with\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":195512,"url":"https:\/\/css-tricks.com\/snippets\/sass\/maintain-aspect-ratio-mixin\/","url_meta":{"origin":191783,"position":5},"title":"Maintain Aspect Ratio Mixin","date":"February 10, 2015","format":false,"excerpt":"This article from July 2013 describes a method of using psuedo elements to maintain an elements aspect ratio, even as it scales. Here's a Sass mixin that simplifies the math a bit. @mixin aspect-ratio($width, $height) { position: relative; &:before { display: block; content: \"\"; width: 100%; padding-top: ($height \/ $width)\u2026","rel":"","context":"With 23 comments","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/pages\/191783"}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/40123"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=191783"}],"version-history":[{"count":10,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/pages\/191783\/revisions"}],"predecessor-version":[{"id":346098,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/pages\/191783\/revisions\/346098"}],"up":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/pages\/191187"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=191783"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=191783"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}