Code Monkey home page Code Monkey logo

Comments (10)

jdanyow avatar jdanyow commented on June 12, 2024

Great question- here's a few options:

brute force

import {HttpClient} from 'aurelia-http-client';
import {employeeComparer} from './employees';

export class Job {
    constructor() {
        this.http = new HttpClient();
    }
    activate(params) {
        return Promise.all([
            this.http.get('/api/jobs/' + params.id).then(http => {
                this.job = JSON.parse(http.response);
            }),
            this.http.get('/api/employees').then(http => {
                this.employees = JSON.parse(http.response);
            })
         ]).then(() => {
             var assignee = this.job.assignee;
             if (assignee) {
                 this.job.assignee = this.employees.filter(employee => employeeComparer(employee, assignee))[0];
             }
         });
     }
}

converter

export class EmployeeToIDConverter {
  toView(employee, employees) {
    return employee ? employee.id : null;
  }
  fromView(id, employees) {
     return id ? employees.filter(e => e.id === id)[0] : null;
  }
}
<select value.bind="job.assignee | employeeToID:employees">
    <option repeat.for="employee of employees" model.bind="employee | employeeToID:$parent.employees">${employee.name}</option>
</select>

enhance Aurelia's select binding logic

Maybe we should add support for an equality-comparer attribute that would be used like this:

<select value.bind="job.assignee" equality-comparer.bind="employeeComparer">
    <option repeat.for="employee of employees" model.bind="employee">${employee.name}</option>
</select>

What do you think?

from binding.

heruan avatar heruan commented on June 12, 2024

Thank you @jdanyow for your suggestions! After further investigation, I'm tempted to use the JSON.parse() optional argument reviver to return the same instance whenever the same object is parsed. That would require a map of retrieved objects (trivial) and a well-written reviver function to handle seamlessly [nested-]arrays and nested-objects (definitely non-trivial).

from binding.

heruan avatar heruan commented on June 12, 2024

I came up to this reviver:

var map = new Map();
var reviver = function(k, v) {
    if (v === null || Array.isArray(v)) return v;
    if (typeof v !== 'object') return v;
    var key = JSON.stringify(v); // this is a simplified strategy to guess object identity
    if (map.has(key)) {
        return map.get(key);
    }
    map.set(key, v);
    return v;
};

applied to the former use case:

import {HttpClient} from 'aurelia-http-client';

export class Job {
    constructor() {
        this.http = new HttpClient();
        this.map = new Map();
        var _map = this.map;
        this.reviver = function(k, v) {
            if (v === null || Array.isArray(v)) return v;
            if (typeof v !== 'object') return v;
            var key = JSON.stringify(v);
            if (_map.has(key)) {
                return _map.get(key);
            };
            _map.set(key, v);
            return v;
        };
    }
    activate(params) {
        return Promise.all([
            this.http.get('/api/jobs/' + params.id).then(http => {
                this.job = JSON.parse(http.response, this.reviver);
            }),
            this.http.get('/api/employees').then(http => {
                this.employees = JSON.parse(http.response, this.reviver);
            })
         ]);
     }
}

and the binding works like a charm (see this gist for a test in NodeJS).

Obviously here I'm guessing object identity based on its string representation (which may vary between the two API requests), but one can use other strategies, e.g. key properties; also, JSON schema may help identifying the type of each property.

from binding.

jdanyow avatar jdanyow commented on June 12, 2024

Cool stuff! One question about the reviver- why not use k as the key instead of stringifying v to produce the key? Apologies if this is a silly question, I don't know anything about revivers.

Edit

stopped being lazy and learned why 💤 Ignore this post...

from binding.

plwalters avatar plwalters commented on June 12, 2024

@jdanyow I'm for adding the third option you listed but with an easier name like matcher :) Even a simple object is having problems matching up.

from binding.

jdanyow avatar jdanyow commented on June 12, 2024

re-opening- @PWKad i like matcher

from binding.

heruan avatar heruan commented on June 12, 2024

I'm using this as a Reviver now, with slight modifications from the previous one:

  • I pass a pk argument which is the /primary key/ (it must be a UUID, unique among collection of different objects);
  • I use Object.assign() to update the current instance of the object.
export class Reviver {
    constructor() {
        this.map = new Map();
    }
    revive(json, pk) {
        var self = this;
        return JSON.parse(json, function(k, v) {
            if (v === null || Array.isArray(v)) return v;
            if (typeof v !== 'object') return v;
            var key = v[pk];
            if (!self.map.has(key)) {
                self.map.set(key, v);
                return v;
            };
            return Object.assign(self.map.get(key), v);
        });
    }
}

I'm still looking for a stronger strategy to discriminate object identity…

P.S. I see Aurelia's http-client uses a reviver in JSON.parse(). Is it configurable?

from binding.

plwalters avatar plwalters commented on June 12, 2024

@heruan The reviver in the http-client is definitely configurable, you can set a shared reviver using .reviver(revfunc) during configuration or per request using .withReviver()

from binding.

32graham avatar 32graham commented on June 12, 2024

I really like the matcher idea. This scenario happens on nearly every page I write for our line-of-business app.

from binding.

jdanyow avatar jdanyow commented on June 12, 2024

http://stackoverflow.com/questions/33920610/binding-a-select-to-an-array-of-objects-in-aurelia

from binding.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.