Categories
discuss

Sort Javascript object by value alphabetically

I have a JS object as follows:

var obj = {"00:11:22:33:44:55" : "AddressB", "66:77:88:99:AA:BB" : "AddressA", "55:44:33:22:11:00" : "AddressC", "AA:BB:CC:DD:EE:FF" : "AddressD"};

The code as follows sorts it alphabetically via key:

sorted = Object.keys(obj)
.sort()
.reduce(function (accSort, keySort) 
{
    accSort[keySort] = obj[keySort];
    return accSort;
}, {});

console.log(sorted);

Which produces the output:

{“00:11:22:33:44:55” : “AddressB”, “55:44:33:22:11:00” : “AddressC”, “66:77:88:99:AA:BB” : “AddressA”, “AA:BB:CC:DD:EE:FF” : “AddressD”}

How can I sort the object alphabetically by value so the output is:

{“66:77:88:99:AA:BB” : “AddressA”, “00:11:22:33:44:55” : “AddressB”, “55:44:33:22:11:00” : “AddressC”, “AA:BB:CC:DD:EE:FF” : “AddressD” }

Answer

You need to sort by the keys by their values first, then, use .reduce to create the resulting ordered object:

const obj = {
  "00:11:22:33:44:55": "AddressB", 
  "66:77:88:99:AA:BB": "AddressA", 
  "55:44:33:22:11:00": "AddressC", 
  "AA:BB:CC:DD:EE:FF": "AddressD"
};

const sorted = Object.keys(obj).sort((a,b) => obj[a].localeCompare(obj[b]))
  .reduce((acc,key) => { acc[key] = obj[key]; return acc; }, {});

console.log(sorted);
Categories
discuss

How should I use Svelte Reactivity with DOM getElementById?

I have a div element where it is scrollable

    <script>
        let scrollBoxObj;
        $: scrollBoxObj = document.getElementById("chat-box");
        
        $: if (!(scrollBoxObj === undefined) && scrollBoxObj.scrollTop < scrollBoxObj.scrollHeight) {
            scrollBoxObj.scrollTop = scrollBoxObj.scrollHeight;
        }
    </script>
    <div id="scrollBox" class="h-screen w-auto chat-box border border-orange rounded">
        <div id="chat-box" style="margin: 0" class="chat-box">
            {#each chatBox as { user, content, type}}
                <MessageBox {user} message={content} {type} />
            {/each}
        </div>
    </div>

    <style>
        .chat-box {
            overflow-y: auto;
        }
    </style>

i am trying to auto scroll down when a new message is added. but it is not reactive. or i didn’t understand how reactivity works in svelte. i also tried to assign scrollBoxObj in onMount but it was still the same result didn’t work.

Answer

In Svelte, the reactivity from $: x = y kicks in when there is a change on the left side from the equation (the y-part).

In your code you have

$: scrollBoxObj = document.getElementById("chat-box");

On the left side we have a string (“chat-box”) which is a constant and will never change, there is also the document which will also never change, this means the reactivity will not work as you expect.

When working with Svelte using document.getElementById (or any of the other selector methods) is considered bad practice because you are interacting directly with the DOM, while your DOM should rather be a reflection of your state. In short: don’t do it.

Svelte provides you with an easy way to bind a DOM-node (like a div) to a variable by simply adding bind:this={variable}

In your case this would become:

<script>
 let scrollbox
</script>

<div bind:this={scrollbox}>
 ...
</div>

The reactive declaration (the if block) will execute whenever anything inside it changes, which is scrollbox in your case:

$: if (scrollBoxObj && scrollBoxObj.scrollTop < scrollBoxObj.scrollHeight) {
  scrollBoxObj.scrollTop = scrollBoxObj.scrollHeight;
}

Just note here again that this will only trigger when scrollbox changes, once it is bound you will not retrigger (for instance when the user scrolls, it will not do anything) for that you should probably use an on:scroll event.

Categories
discuss

Why can’t enum and record be combined?

Recently I was just creating another enum type. I took advantage of the fact that in Java, an enum is a special type of class (and not a named integer constant, like in C#). I made it with two fields, an all-arg constructor and getters for both fields.

This is an example:

enum NamedIdentity {

    JOHN(1, "John the Slayer"),
    JILL(2, "Jill the Archeress");

    int id;
    String nickname;

    NamedIdentity(int id, String nickname) {
        this.id = id;
        this.nickname = nickname;
    }

    id id() {
        return this.id;
    }

    String nickname() {
        return this.nickname;
    }
}

Then I thought that Java 14’s record keyword would have saved me the boilerplate code that this feature was trying to save me. This, as far as I know, doesn’t combine with enums. If enum records would have existed, the abovementioned code would then look like this:

enum record NamedIdentity(int id, String nickname) {
    JOHN(1, "John the Slayer"),
    JILL(2, "Jill the Archeress");
}

My question is: is there a reason that enum records don’t exist? I could imagine several reasons, including, but not limited to:

  • The number of use-cases for this feature would be too small, the Java language would benefit more if we, as Java language designers, designed and implemented other features.
  • This is hard to implement, due to the internal implementation of the enum type.
  • We, as Java language designers, simply didn’t think about this, or we have not received such a request from the community yet, so we didn’t prioritize it.
  • This feature would have semantical issues, or the implementation of this feature could cause semantic ambiguity or otherwise confusion.

Answer

tl;dr

  • Technical limitation: Multiple inheritance prevents mixing Enum with Record superclasses.
  • Workaround: Keep a record as member field of your enum
NamedIdentity.JILL.detail.nickname()  // ➣ "Jill the Archeress"

Multiple inheritance

You asked:

is there a reason that enum records don’t exist?

The technical reason is that in Java, every enum is implicitly a subclass of Enum class while every record is implicitly a subclass of Record class.

Java does not support multiple inheritance. So the two cannot be combined.

Semantics

But more important is the semantics.

An enum is for declaring at compile time a limited set of named instances. Each of the enum objects is instantiated when the enum class loads. At runtime, we cannot instantiate any more objects of hat class (well, maybe with extreme reflection/introspection code, but I’ll ignore that).

A record in Java is not automatically instantiated. Your code instantiated as many objects of that class as you want, by calling new. So not at all the same.

Boilerplate reduction is not the goal of record

You said:

I thought that Java 14’s record keyword would have saved me the boilerplate code

You misunderstand the purpose of record feature. I suggest you read JEP 395, and watch the latest presentation by Brian Goetz on the subject.

As commented by Johannes Kuhn, the goal of record is not to reduce boilerplate. Such reduction is a pleasant side-effect, but is not the reason for the invention of record.

A record is meant to be a “nominal tuple” in formal terms.

  • Tuple means a collection of values of various types laid out in a certain order, or as Wikipedia says: “finite ordered list (sequence) of elements”.
  • Nominal means the elements each have a name.

A record is meant to be a simple and transparent data carrier. Transparent means all its member fields are exposed. It’s getter methods are simply named the same as the field, without using the get… convention of JavaBeans. The default implantation of hashCode and equals is to inspect each and every member field. The intention for a record is to focus on the data being carried, not behavior (methods).

Furthermore, a record is meant to be shallowly immutable. Immutable means you cannot change the primitive values, nor can you change the object references, in an instance of a record. The objects within a record instance may be mutable themselves, which is what we mean by shallowly. But values of the record’s own fields, either primitive values or object references, cannot be changed. You cannot re-assign a substitute object as one of the record’s member fields.

  • When you have a limited set of instances known at compile time, use enum.
  • When you are writing a class whose primary job is to immutably and transparently carry a group of data fields, use record.

Worthy question

I can see where the two concepts could intersect, where at compile time we know of a limited set of immutable transparent collections of named values. So your question is valid, but not because of boilerplate reduction. It would be interesting to ask Brian Goetz or others on the Java team if they ever discussed the notion.

Workaround: Store a record on your enum

The workaround is quite simple: Keep a record instance on your enum.

You could pass a record to your enum constructor, and store that record as a member field on the enum definition.

Make the member field final. That makes our enum immutable. So, no need to mark private, and no need to add a getter method.

First, the record definition.

package org.example;

public record Performer(int id , String nickname)
{
}

Next, we pass an instance of record to the enum constructor.

package org.example;

public enum NamedIdentity
{
    JOHN( new Performer( 1 , "John the Slayer" ) ),
    JILL( new Performer( 2 , "Jill the Archeress" ) );

    final Performer performer;

    NamedIdentity ( final Performer performer ) { this.performer = performer; }
}

If the record only makes sense within the context of the enum, we can nest the two together rather than have separate .java files. The record feature was built with nesting in mind, and works well there.

Naming the nested record might be tricky in some cases. I imagine something like Detail might do as a plain generic label if no better name is obvious.

package org.example;

public enum NamedIdentity
{
    JOHN( new Performer( 1 , "John the Slayer" ) ),
    JILL( new Performer( 2 , "Jill the Archeress" ) );

    final Performer performer;

    NamedIdentity ( final Performer performer ) { this.performer = performer; }

    public record Performer(int id , String nickname) {}
}

To my mind, this workaround is a solid solution. We get clarity in the code with the bonus of reducing boilerplate. I like this as a general replacement for keeping a bunch of data fields on the enum, as using a record makes the intention explicit and obvious. I expect to use this in my future work, thanks to your Question.

Let’s exercise that code.

for ( NamedIdentity namedIdentity : NamedIdentity.values() )
{
    System.out.println( "---------------------" );
    System.out.println( "enum name: " + namedIdentity.name() );
    System.out.println( "id: " + namedIdentity.performer.id() );
    System.out.println( "nickname: " + namedIdentity.performer.nickname() );
}
System.out.println( "---------------------" );

When run.

---------------------
enum name: JOHN
id: 1
nickname: John the Slayer
---------------------
enum name: JILL
id: 2
nickname: Jill the Archeress
---------------------
Categories
discuss

nextjs nested dynamic folder routing

Update:

  1. Which it causing this error because of [category_slug]-index.js that getServerSideProps?
  2. I tried to do index.js under product folder, it works, mean it okies with [category_slug] which getServerSideprops, am I right?

This is my folder structure

pages
   |-categories
       |-[category_slug]
           |-index.js     
           |-product
               |-[product_slug].js       

It causes an error when I enter in [product_slug]. Showing:

Error: A required parameter (category_slug) was not provided as a string in getStaticPaths for /categories/[category_slug]/product/[product_slug]

Would this possible to do nested routing folder in Next.js? I can’t find any info for this. I’m showing my code in below.

// [product_slug].js

export async function getStaticProps({ params: { product_slug } }) {
  const product_res = await fetch(
    `${API_URL}/products/?product_slug=${product_slug}`
  ); // question mark is query slug, to find the slug in the json
  const found = await product_res.json();

  return {
    props: {
      product: found[0],
    }
  };
}

export async function getStaticPaths() {
  // Retrieve all the possbile paths
  const products_res = await fetch(`${API_URL}/products/`);
  const products = await products_res.json();

  return {
    paths: products.map((product) => ({
          params: { product_slug: product.product_slug },
        }),
    fallback: false, 
  };
}

I tried to provide a hardcoded value to [category_slug]. Would it be correct in this way? I am not sure also. I couldn’t find about this in the docs.

export async function getStaticProps({ params: { product_slug } }) {
  const product_res = await fetch(
    `${API_URL}/products/?product_slug=orange_juice`
  ); 

  const found = await product_res.json();

  return {
    props: {
      product: found[0],
    },
  };
}

export async function getStaticPaths() {
  // Retrieve all the possbile paths
  const products_res = await fetch(`${API_URL}/products/`);
  const products = await products_res.json();

  return {
    paths: [
      {
        params: {
          product_slug:
            "categories/orange/product/orange_juice",
        },
      },
    ],
    fallback: false,
  };
}

Can anyone provide a right way to input first dynamic path in [product_slug] dynamic route?

Answer

As @ckoala mentioned you just need to retrieve the possible category_slugs in your [product_slug]‘s getStaticPaths.

I assume, based on your routing structure, that each product belongs to a given category. In that case, you’d need to fetch all products for each category in the getStaticPaths.

// categories/[category_slug]/product/[product_slug].js

export async function getStaticPaths() {
    // Add your logic to fetch all products by category

    return {
        paths: [
            // For each category/product combination you would have an entry like the following:
            {
                params: {
                    category_slug: 'orange'
                    product_slug: 'orange_juice',
                }
            }
        ],
        fallback: false
  };
}

Your getStaticProps would then also expect the additional category_slug param.

export async function getStaticProps({ params: { category_slug, product_slug } }) {
    // Add logic to fetch a single product based on `category_slug` and/or `product_slug`

    return {
        props: {
            product
        }
    };
}

Given the entry used as an example in getStaticPaths you’d be able to access the following path: /categories/orange/product/orange_juice.

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..