質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.11%

TypeScript配列の特殊なソート

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,305

akao

score 51

少し説明が難しいのですが、なるべくコードなども簡略化してみますので、読んでくだされば幸いです(T_T)

https://github.com/holiber/sl-vue-tree

↑こちらの、リストのソートをするライブラリを使用しました。

//拡張子は.vueです。vueクラスコンポーネントを使ってます。

<template>
  <div class="objectList">
        <div class="objectArea">
          <SlVueTree ref="SlVueTree" v-model="objectList">

          </SlVueTree>
        </div>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";

import SlVueTree from 'sl-vue-tree'


@Component({
  components: {
    SlVueTree
  }
})

export default class ObjectList extends Vue {


  get objectList() {
      return this.$store.getters.objectList;
  }

  set objectList(updatedObjectList) {
      this.$store.dispatch('edit/sortObjectList' , updatedObjectList)
  }
}
</script>

<style lang="scss">

</style>

vuexとこちらのライブラリを組み合わせる場合、上のように、getとsetを使います。
setはドラッグ&ドロップした時に呼ばれます。

set objectList(updatedObjectList) {
this.$store.dispatch('edit/sortObjectList' , updatedObjectList)
}

↑ここでは、ソートされた結果(updatedObjectList)を元々のobjectListに格納しています。
(objectList = updatedObjectListみたいなことをする)
そうすることで、

get objectList() {
return this.$store.getters.objectList;
}

ここが変化し、ソートができます。
データはgetとバインドされています。

しかし、こちらのライブラリ、
objectListのモデルに含まれた"関数"に関しては、updatedObjectListに入ってくれないです。
updatedObjectListに入ってくれるのはプロパティのみです。

したがって、

objectList=updatedObjectList

のように上書きするのではなく、

元々のobjectListをupdatedObjectListに従ってソートするということをしたいです。

例えば、

元々のobjectListが

let objectList = [

  {
    objectId : 1,
    objectName : "オブジェクト1",
    objectList : [],
    isLeaf : false,
    children : []
  },
  {
    objectId : 2,
    objectName : "オブジェクト2",
    objectList : [],
    isLeaf : true
  },
  {
    objectId : 3,
    objectName : "オブジェクト3",
    objectList : [],
    isLeaf : false, 
    children : []
  },
  {
    objectId : 4,
    objectName : "オブジェクト4",
    objectList : [],
    isLeaf : true
  },
  {
    objectId : 5,
    objectName : "オブジェクト5",
    objectList : [],
    isLeaf : false,
    children : []
  },

]

で、updatedObjectListが

let updatedObjectList = [
  {
    objectId : 5,
    objectName : "オブジェクト5",
    objectList : [],
    isLeaf : false,
    children : []
  },
  {
    objectId : 3,
    objectName : "オブジェクト3",
   objectList : [],
    isLeaf : false,
    children : [
      {
        objectId : 2,
        objectName : "オブジェクト2",
        objectList : [],
        isLeaf : true
      },
      {
        objectId : 1,
        objectName : "オブジェクト1",
        objectList : [],
        isLeaf : false,
        children : [
          {
            objectId : 4,
            objectName : "オブジェクト4",
            objectList : [],
            isLeaf : true
          },
        ]
      },
    ]
  }
]

だった場合、

objectList = updatedObjectListとするのではなく

"objectListをソートして、"updatedObjectListと同じ構造にするためにはどのようにすればよろしいでしょうか。

親になることができるobjectは

isLeaf : false

というパラメーターを持ちます。
そして、子はchildrenという名前のパラメーターに入ります。
しかし、childrenに格納することに加えて、同じものを、objectListというパラメーターに格納したいです。
linq-es2015という,typescript用のlinqモジュールも使えますので、linqを使うこともできます。
ただc#のlinqと全く同じメソッドが定義されている訳ではありません。

-追記-

dataにプロパティで任意のプロパティを持っても、関数が渡されなかった
以下はvuexのルートモデルの一部

import { ImageObject } from './image/imageObject'

import { ObjectData } from './objectData'

export class Object{

    public title : string = ""

    public isLeaf : boolean = true

    public data : ObjectData = new ObjectData("")

    constructor(object : {objectType : string , objectId : number}){

        if(object.objectType == "imageObject"){
            this.data = new ImageObject(object)
            //imageObjectはobjectDataをextendしている
        }
    }

}
import { OuterRect } from './rect/outerRect'

/** 挿入データ(文字とか画像とか)の状態のうち、全てのデータで共有する要素 */
export class ObjectData{

    public objectId : number = 0

    public objectType : string = ""

    public name : string = ""

    public selected : boolean = false

    public outerRect : OuterRect = new OuterRect("string")  

    constructor(objectType : string){
        this.objectType = objectType
        if(objectType!=""){
            this.outerRect = new OuterRect(objectType)
        }
    }

    public changeState(state : { value : string , stateType : string }){


    }

}

このようにobjectDataにも関数はありますし、outerRectにも関数があるのですが、それらが順番を変えたりすると(objectList = updatedObjectListをすると)、消えてしまいます。

data.outerRect.function is not a function とエラーが出てしまいます。

-追記-

そしてやはり並び替えだとうまくいきます

let objectList = this.objectList

this.objectList = []

for(var i = 0; i < updatedObjectList.length; i++){
            this.objectList.unshift(Enumerable.asEnumerable(objectList).Where(x=>x.objectId==updatedObjectList[i].objectId).ToArray()[0])
}

ただし、これはグループ化をしておらず、一階層目だけでオブジェクトを入れ替えているだけです。
階層構造も含めて
updatedObjectと同じ構造にしたいです...

-追記-
https://ja.stackoverflow.com/questions/47499/typescript-%E9%85%8D%E5%88%97%E3%81%AE%E7%89%B9%E6%AE%8A%E3%81%AA%E3%82%BD%E3%83%BC%E3%83%88

こちら、スタックオーバーフローにほとんど同じ質問をしたところ、マルチポストであるというご指摘を頂きました。
配列をソートする方法自体に関しては、スタックオーバーフローの方で回答をいただけました。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

ノードの型が下記のインターフェイスで定義されているので、data プロパティに任意のデータを持たせれば良いのではないでしょうか。たぶん関数でも問題なく保持されます。インターフェイスに定義されていない objectId なども data プロパティに移したほうが良いかなと思います。

interface ISlTreeNodeModel<TDataType> {
    title: string;
    isLeaf?: boolean;
    children?: ISlTreeNodeModel<TDataType>[];
    isExpanded?: boolean;
    isSelected?: boolean;
    isDraggable?: boolean;
    isSelectable?: boolean;
    data?: TDataType;
}
interface ISlTreeNode<TDataType> extends ISlTreeNodeModel<TDataType> {
    isVisible?: boolean;
    isFirstChild: boolean;
    isLastChild: boolean;
    ind: number;
    level: number;
    path: number[];
    pathStr: string;
    children: ISlTreeNode<TDataType>[];
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/14 20:17 編集

    なるほどです、実際に呼ばれてるのはminの方なのですね...。
    提示してくださった手順のうちの3のビルドというのは、
    このminを作り直すということでしょうか。
    普通に npm run build コマンドを利用すると、distフォルダが作られて、その中身をサーバーにアップロードすることでwebアプリをそのサーバーで使えるようになると思うのですが、ライブラリやモジュールを書き換えることとどう関連するのでしょうか。

    キャンセル

  • 2018/08/14 22:57

    npm run build するのはライブラリのディレクトリ内で、です。src 以下のファイルを編集しても実際に読み込まれるのは minify されたほうなのでライブラリのほうをビルドしなおす必要があるということです。

    キャンセル

  • 2018/08/15 09:38

    なるほどです!!!
    分かってきました。
    ライブラリのディレクトリ内でnpm run build のコマンドが使え、そしてそれでminファイルをビルドできるとは知りませんでした。
    やっと提示してくださった6っつの手順の意味が分かってきました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.11%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる