GithubHelp home page GithubHelp logo

aurelia-breeze's People

Contributors

jdanyow avatar jeroenvinke avatar rockresolve avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aurelia-breeze's Issues

BreezePropertyObserver sets entity propertyChangedEventArgs propertyName

Symptom: other subsequent breeze entity PropertyChanged subscriptions get propertyChangedEventArgs with a random propertyName for an entity-wide change when it should be blank

Cause: aurelia-breeze subscribes to the Breeze propertyChanged event. If it is an entity event, during its processing the handleEvent method is setting the propertyName. When it exits it leaves a random propertyName in the propertyChangedEventArgs "change" object parameter.

e.g. mergeEntity after manager.saveChanges() raises PropertyChanged event on an entity with entityState.isUnchanged. Subscriptions after aurelia-breeze see these events with a random propertyName.

Use Case: I need to know of any propertyChange, and as I sometimes start with an added entity I cant use entityState changes. As I want any property change I dont want to subscribe to every properties observer.

how to integrate aurelia-breeze into skeleton-typescript-aspnetcore(skeleton-navigation-1.1.1)?

I want to build an app with the skeleton-typescript-aspnetcore and use breeze. The skeleton works fine, but when I followed the aurelia-breeze guide to set breeze up, I used
import breeze from 'breeze';
in a ts file, but got an error: cannot found module 'breeze', and then I googled for a while and found the d.ts file in dist folder(https://github.com/jdanyow/aurelia-breeze/tree/master/dist), but after adding the file, a new error- cannot find module 'breeze-client' - appeared, which came from the d.ts file. I checked the package.json, it has the both aurelia-breeze and breeze-client in dependencies section, but the typings.json not.

also, I found the content of aurelia-breeze.d.ts file is not similar as other index.d.ts file in typings folder(like: typings/modules/aurelia-binding/index.d.ts), they all have a typings.json file.

can you give me a hint how to make it work with the skeleton, thanks in advance.

The plugin won't load.

Hi, here is the stacktrace I get when I add aurelia-breeze to my app :

DEBUG [aurelia] Loading plugin aurelia-breeze.

es6.promise.js:139 Unhandled promise rejection Error: Error invoking TaskQueue. Check the inner error for details.

inner error: TypeError: _aureliaPal.DOM.createMutationObserver is not a function
at makeRequestFlushFromMutationObserver (http://localhost:9000/jspm_packages/npm/[email protected]/aurelia-task-queue.js:13:36)
at new TaskQueue (http://localhost:9000/jspm_packages/npm/[email protected]/aurelia-task-queue.js:59:41)

Id there a precise version of aurelia-pal, having a createMutationObserver ?

Aurelia is the configured this way :
aurelia.use
.standardConfiguration()
.developmentLogging()
.plugin("aurelia-breeze")
.feature("resources");

I have added the following dependencies :
"aurelia-binding": "npm:aurelia-binding@^1.0.0-beta.1.0.1",
"aurelia-bootstrapper": "github:aurelia/bootstrapper@^0.18.0",
"aurelia-breeze": "npm:aurelia-breeze@^0.13.1",
"aurelia-dependency-injection": "npm:aurelia-dependency-injection@^1.0.0-beta.1",
"aurelia-event-aggregator": "npm:aurelia-event-aggregator@^1.0.0-beta.1",
"aurelia-framework": "github:aurelia/framework@^0.17.0",
"aurelia-http-client": "npm:aurelia-http-client@^1.0.0-beta.1",
"aurelia-logging-console": "github:aurelia/logging-console@^0.8.0",
"aurelia-router": "github:aurelia/router@^0.13.0",
"bootstrap": "github:twbs/bootstrap@^3.3.5",
"breeze": "npm:breeze-client@^1.5.5",
"font-awesome": "npm:font-awesome@^4.4.0",
"jonmiles/bootstrap-treeview": "github:jonmiles/bootstrap-treeview@^1.2.0",
"jquery": "github:components/jquery@^2.1.4"

Thank you

ajax-adapter should self-register with Breeze?

It is conventional for the file that defines a new adapter to "self-register" that adapter with Breeze ... a step that must be taken eventually anyway.

Here is the line I was expecting to see, perhaps near the bottom of the file:

breeze.config.registerAdapter("ajax", AjaxAdapter);

And having done that, there would be no need to register it as you do later in index.js and no reason to export AjaxAdapter at all.

Any reason you went this other way?

Perhaps you were thinking testing? Well the standard way any consumer of breeze would access this adapter is by requesting it from Breeze

var ajaxAdapter = breeze.config.getAdapterInstance("ajax", 'aurelia'); // get the current instance
var AjaxAdapter = breeze.config.getAdapter("ajax", 'aurelia'); // get the constructor function (rare)

That's how I'd do it in my tests ... in part because in tests I want to follow as closely as I can the way I expect developers to work with this component.

Thoughts?

BreezeObservationAdapter.handles Property tweak?

Why check both entityAspect and entityType? Why not assume that if an object has an entityType, it must be a breeze entity. Who else is going to define that property for an object in an application that uses Breeze?

Could replace this:

// breeze entities have entityAspect and entityType properties.
if (!object.entityAspect || !(entityType = object.entityType))
  return false;

// get or create the lookup used to avoid reflecting on the breeze entityType multiple times.
canObserve = entityType.__canObserve__ || createCanObserveLookup(entityType);

// return canObserve- coerce undefined values to false.
return !!canObserve[propertyName];

With this:

var type = object.entityType
return type ? !!(type.__canObserve__ || createCanObserveLookup(type))[propertyName] : false;

Interaction with aurelia-validation

Hi there,

I'm wondering how do you want to integrate this plugin with aurelia-validation (as it's seems to be the next aurelia big step).

Do you have any plan to merge both validation systems (breeze & aurelia-validation) ? Because I've started a JSData v3 plugin and I don't want to duplicate the validation system in model & controller layer.

errorCallback from breeze manager.ExecuteQuery not executed

If I call an API (which throws an exception) using breeze's executeQuery method, the errorCallback function is never called.

var eq = new breeze.EntityQuery('TestError'); instance.manager.executeQuery( eq, function(data) { console.log('success') }, function(err) { debugger; });

this is api method

[HttpGet] public void TestError() { throw new Exception("test exception"); }

nor does it work with what is described here (see executeQuery method)

I suppose this is because aurelia-breeze replaces Q with ES6 Promises.
Is it possible to have the errorCallback called anyway? Or am I just doing something wrong?

I am not sure if this has to do with this issue:
#44
If so, please feel free to remove this issue.

Does ajax-adapter accidentally overwrite headers in config?

This line concerns me:

requestInfo.config.headers = clone(this.defaultHeaders || {});

That will *_replace_ rather than extend any headers that happen to be specified in the config from the caller. Now I admit that there will be no such headers when the caller is the breeze EntityManager ... at least as of today. But that could change and maybe someone else wants to use this adapter for some reason.

That's why we play it safe in other ajax adapter implementations ... like this:

var core = breeze.core;
var headers = core.extend({}, this.defaultSettings.headers); // copy default headers 1st
requestInfo.config.headers = core.extend(headers, requestInfo.config.headers);

Tweaks to BreezeObservationAdapter methods

While investigating splice-vs-null setting (see this issue), I tripped over a few adjustments you might want to make.

All of them can be found in this gist.

subscribe

Instead of repeatedly executing this.callbacks[propertyName], I would capture that array. Your splicing version would look like this:

function subscribe(propertyName, callback){
    var callbacks = this.callbacks[propertyName];
    if (!callbacks) {
      this.callbacks[propertyName] = [callback];
    } else if (callbacks.indexOf(callback) === -1) {
      callbacks.push(callback);
    } else {
      return; // already registered; ignore.
    }

    if (this.callbackCount === 0) {
      this.subscription = this.obj.entityAspect.propertyChanged.subscribe(this.handleChanges.bind(this));
    }

    this.callbackCount += 1;

    return this.unsubscribe.bind(this, propertyName, callback);
}

I think you are correct to ignore an attempt to re-register the same callback function rather than throw. OTOH, I prefer moving the elses around because I find it easier to read a positive (=== -1) rather than a negative (!=== -1). Don't you?

unsubscribe

Instead of calculating the index of the callback twice, I would call it once.

I guard against a failure to find the callback for a particular property, whether that's because the callback isn't registered or because there aren't any subscriptions for that property. Both cases I treat as "no-ops".

I also think it is safer (from a memory leak perspective) to zap the this.callbacks when there are no more subscriptions.

My revised version looks like this:

function unsubscribe(propertyName, callback) {
    var callbacks = this.callbacks[propertyName];
    if (!callbacks) { return; } // no subscriptions for this property; ignore.
    var index = callbacks.indexOf(callback);
    if (index === -1) { return; } // this callback was not found; ignore.
    callbacks.splice(index, 1);
    this.callbackCount -= 1;
    if (this.callbackCount === 0) {
      this.obj.entityAspect.propertyChanged.unsubscribe(this.subscription);
      this.callbacks={};
    }
}

Per Crockford, I'm using this.callbackCount += 1 and this.callbackCount -= 1 instead of this.callbackCount++ and this.callbackCount--. That change is really picky.

Installing 0.13.0 fails

Installation using jspm install npm:aurelia-breeze fails with the following error:

Looking up npm:aurelia-breeze
     Updating registry cache...
     Downloading npm:[email protected]

warn Error on processPackageConfig
     Package.json dependency aurelia-binding set to npm:aurelia-binding@^1.0.0-beta.1, which is not a valid dependency format for npm.
     It's advisable to publish jspm-style packages to GitHub or another registry so conventions are clear.

err  Error: Error processing package config for npm:aurelia-breeze.
         at /Users/BBosman/Development/ExternalApps/Aurelia/node_modules/systemjs-builder/lib/builder.js:27:9
         at Object.lib$rsvp$events$$default.trigger (/Users/BBosman/Development/ExternalApps/Aurelia/node_modules/rsvp/dist/rsvp.js:245:13)
         at null._onTimeout (/Users/BBosman/Development/ExternalApps/Aurelia/node_modules/rsvp/dist/rsvp.js:779:47)
         at Timer.listOnTimeout (timers.js:92:15)

err  Error processing package config for npm:aurelia-breeze.

warn Installation changes not saved.

Trying out breeze-validation custom attribute

I put together a skeleton project with an MVC/EF backend.

The database has just one table with two fields, FirstName and LastName. The last name has the Required attribute.

I then had the EntityManager fetch the metadata which included a nullable:false for LastName which then should be validated in the UI.

It all wired up OK and I can save the contact to the database.
However, when I add "breeze-validation.bind='currentContact'", it throws the following error:

TypeError: Cannot read property 'subscribe' of undefined
at BreezeValidation.subscribe (http://localhost:56321/jspm_packages/github/jdanyow/[email protected]/breeze-validation.js:104:70)

Stepping through the code in the debugger, it shows that the subscribe function is expecting and entityManager, but it is getting the entity instead.

This is the line of code that throws an error:
this.errorsSubscription = entityManager.validationErrorsChanged.subscribe

This is the viewmodel:

import breeze from "breeze";

export class Welcome {
  currentContact;
  manager;

  constructor() {
      this.manager = new breeze.EntityManager('breeze/data');
      this.manager.fetchMetadata().then(() => {

          this.currentContact = this.manager.createEntity("Contact");
          this.currentContact.FirstName = "Greg";
          this.currentContact.LastName = "Gum";

      });
  }

  submit() {
      this.manager.saveChanges();
  }


} 

if.bind conflict ?

<div class="form-horizontal" breeze-validation.bind="newItem" show.bind="!readOnly"> all is ok!</divb>

<div class="form-horizontal" breeze-validation.bind="newItem" if.bind="!readOnly"> the form start validated!</div>

Validation error

The current version of aurelia-breeze 2.2.0 does not work correctly with this example (https://plnkr.co/edit/XMmSqT?p=preview), it validates but does not render the error. Is there any fix that I can do? Any other example with a more current version? Do you have any other way to show your mistakes? thank you

Obs: the last version that I managed to make it work was 1.0.0

Make unsubscribe flyweight

The current unsubscribe method returned from a subscription is kind of heavy and holds several captures.

return function() {      
    callbacks.splice(callbacks.indexOf(callback), 1);
    if (callbacks.length > 0)
        return;
    this.obj.entityAspect.propertyChanged.unsubscribe(this.subscription);
    this.observing = false;
}.bind(this);

This might matter because you'll create so many of them.

I'd rather see it be ...

return function() {this.unsubscribe(callback, propertyName);}.bind(this);

and delegate the details to unsubscribe.

Better still if you write:

callback.propertyName = propertyName;
return function() {this.unsubscribe(callback);}.bind(this);

“Q js is undefined.” while trying to resolve promise from aurelia-breeze in test method(karma+jasmine)

I am consistently getting an error while trying to resolve a promise from aurelia-breeze in a test method for an aurelia(typescript + breeze) application.

Testing framework used is karma+jasmine.
Version of the aurelia-breeze package is 1.0.0

Aurelia breeze makes use of es promise resolver instead of Q.js, but the test method is searching for Q.js to resolve the promise returned from breeze.

I have tried to add the Q library to the window object from the spec file. But the breeze.debug.js is trying to access the Q js from the window object before it is set in the spec file.
this didn't resolve the issue.

Please help me to solve this issue.

User Authentication

I am using this Aurelia Breeze plugin.

My use case is that I have to pass Uer Name/Password to the REST API that I am consuming for Authentication.

Could you please show a direction on how I can achieve the authentication. Googled a lot, but left clueless

Issue when building with Aurelia-CLI

Not sure if this is an issue here, or with aurelia-bundler...

I've tried creating a new project using the new release version of the cli tool (Typescript, default settings for everything else) and then adding aurelia-breeze (adding that, aurelia-fetch-client and breeze-client to the dependencies in aurelia_project/aurelia.json). When I do au build it looks like it's deriving the wrong filename for breeze - which should be breeze.min.js

Tracing aurelia-binding...
Tracing aurelia-bootstrapper...
Tracing aurelia-breeze...
error D:\dev\AuTest\BreezeTest\node_modules\breeze-client\breeze.js
Tracing aurelia-event-aggregator...
Tracing aurelia-dependency-injection...
Tracing aurelia-framework...
Tracing aurelia-history...

Error with webpack skeleton

Hi,
I'm trying to setup this plugin with the webpack skeleton app, it does well when webpack creates the bundles, but then when I run the app throws an error:

Unhandled rejection Error: Cannot find module './aurelia-breeze/validation/breeze-validation'

I think the problem is when it executes this line: frameworkConfig.globalResources('./validation/breeze-validation');

Maybe I should register breeze-validation as a plugin in my aurelia config?

The aurelia-breeze.d.ts file is missing after installing

I used the navigation skeleton for asp dot net to build an app, and it runs well, then I want integrate breeze. I followed the guide but get an error : cannot find the module 'aurelia-breeze', according to other issues, I am sure it is caused by the missed ts file, but I cannot find it, is there a way to make work? thanks.

Why does ajax-adapter have static setHttpClientFactory function?

The adapter definition has this static method (setHttpClientFactor) for defining the method that will determine the runtime instance of the httpClient used by the adapter.

I'm personally leery of statics, especially when there is no default implementation. I don't see the need in this case. IMO, it should be an adapter instance method such as;

setHttpClient(client) {
    this.client = client;
}

Configuration now looks like this:

var adapter = breeze.config.initializeAdapterInstance('ajax', 'aurelia', true);
adapter.setHttpClient(aurelia.container.get(HttpClient));

That's the way it's done with the Angular ajax adapter. It seems clearer to me and slightly easier to test. And it's one fewer method to export.

Thoughts?

Why does ajax-adapter export `HttpResponse`?

Who needs it? It's really an object whose definition is internal to breeze itself. It's really a "private" contract between an ajax adapter and the Breeze EntityManager.

You don't use it elsewhere in the repo and know consumer of Breeze should know it exists.

I recommend minimizing exports as much as possible.

If you combine this with my other recommendations, you'll have a module that exports an empty object. Nothing wrong with that IMO. It's a module with a side-effect; it defines an adapter and registers it with Breeze.

latest webpack skeleton config

Hi,

I have used the newest aurelia with same webpack config as latest typescript skeleton

get error
cannot read property extend of undefined
in file node_modules/aurelia-breeze/dist/commonjs/aurelia-breeze
var extend = _breeze2.default.core.extend;

using "aurelia-breeze": "^1.2.0",

Greetings
Felix

Return the instance of breeze from the Configure Method

This file https://github.com/jdanyow/aurelia-breeze/blob/master/dist/aurelia-breeze.js, has a method called configure.

The only way I have found to get webpack and aurelia-breeze to work together involves modifying this file to return the instance of breeze that is configured in there. I then can use that instance in my application.

Would you be willing to make this modification. It can be done by adding:

 return breeze;

as the last line before the method closes? (Right after adapter.setHttpClientFactory(() => frameworkConfig.container.get(HttpClient));.)

Setting default Header does not seem to work

I am trying to set a custom header (an Auth Header) but I don't see the header being passed to the server:

var ajaxAdapter: any = breeze.config.getAdapterInstance('ajax');
ajaxAdapter.defaultSettings = { headers: { "X-Test": "123" } };

Have also tried:

var ajaxAdapter: any = breeze.config.getAdapterInstance('ajax', 'aurelia');
ajaxAdapter.defaultSettings = { headers: { "X-Test": "123" } };

Any idea what is going on?

Typescript compile error

The current aurelia-breeze.d.ts file has this as the first line:

import breeze from 'breeze-client';

This gives me the error:

ERROR in C:\my\path\my-project\node_modules\aurelia-breeze\dist\aurelia-breeze.d.ts
(1,8): error TS1192: Module '"C:/my/path/my-project/node_modules/breeze-client/index"' has no default export.

If I change the first line to this:

import * as breeze from 'breeze-client';

Then it works fine.

Please consider changing this in the source.

2.2.0 has broken error processing

The "ajax adapter didn't report error properly" v2.2.0 commit no longer sets an error's data.
Use case: 500 errors (e.g. invalid save) no longer return error.message.

The commit no longer processes response.json in promise reject.
While the standard fetch api only returns network errors via the promise reject, aurelia-fetch adds a response rejectOnError interceptor. The interceptor returns any response with ok = false via the promise reject.

I am not sure how to correct as I dont know what the "ajax adapter didn't report error properly" problem was that this commit was trying to fix. I cant find the issue.

Add Webpack setup to the readme.md

The readme.md file only shows how to setup using JSPM.

It would be really nice to see how this should be setup for Webpack. (I get a breeze is not defined error.)

Entity query withParameters error

I'm trying to execute a query with parameters, but the generated url is wrong:

http://localhost:16746/api/v1/CountryItem?$orderby=Id&$top=10&$inlinecount=allpages?q=Sa


        let manager = new breeze.EntityManager('/api/v1');

        var query = breeze.EntityQuery
            .from('CountryItem')
            .withParameters({
                q: 'Sa'
            })
            .orderBy('id')
            .skip(0)
            .take(10)
            .inlineCount();

        manager.executeQuery(query.using(breeze.FetchStrategy.FromServer), data => {
            return data;
        });

Is this a bug or I'm doing something wrong?

Error messages need to be configurable

When I put the Required attribute on a Entity Model, an appropriate error message is displayed.

[Required]
LastName string {get;set;}

For example, on the LastName field, I get a LastName is required message.

However, what would be even better is if the message was taken from the Required attribute:

[Required(ErrorMessage = "Last Name is required.")]
public string LastName { get; set; }

For a production app, these details are important such as a user friendly field name and a period at the end.

However, I don't think breeze actually supports this. The message does not get included in the metadata. I know there was discussion about this in the past on the breeze site, as I tried to resolve this once before and gave up on it and stopped using annotations and instead use Aurelia-validation so it is all configured on the client. But perhaps we could get Ward to consider adding this in to breeze.

But the point is, I can't use breeze-validation.bind without some way of being able to configure the error messages, either on the client or the server.

I would love to use just breeze-validation, and not use Aurelia-validation if that is possible.

aurelia-breeze, typescript (and webpack)

I have tried everything I can think of and cannot get aurelia-breeze, breeze and typescript to play together. I've tried re-editing the type definitions and all sorts... I just always end up with errors along the lines of...
node_modules/breeze-client/breeze.debug".export=' has no exported member 'EntityManager'.

Also my understanding is that I need to still use the webpack alias fix, but... if I do that I have to reference the import as breeze (instead of the real breeze-client), and then typescript can no longer find it...

Pulling my hair out here... any help greatly appreciated!

Queries don't return any results in IE9

When running in IE9, the results part of my query comes back as an empty array. This causes a promise rejection when the promise tries to resolve an undefined entity. The network response shows that all the results are there. The response is exactly the same as other browsers where the app works.

The same app works fine in IE11 and Chrome.

Extracting Metadata with error involving 'isPrototypeOf'

I am trying to implement the aurelia-breeze library into a new aurelia application, and when the first query is run, the library is trying to download the Metadata and it fails returning the error:

"Metadata query failed for: http://localhost:8080/api/CE/CE/Metadata; TypeError: Cannot read property 'isPrototypeOf' of undefined"

I have been successful in hitting that same service using basic Breeze, but I found this library and thought I would implement it to take advantage of some of the out of the box features. (e.g. removing Q from the list of libraries, etc)

I'm using the entity-manager-factory to encapsulate the entityManager as seen in the aureliea-breeze-northwind demo. It is used by a service object to extract the data from my web.api. Here is the service object:

import breeze from 'breeze';
import {createEntityManager} from '../entity-manager-factory';

export class PartyDataService {

    /**********************************************
     * loadExistingHospital
     * id - integer Id of the hospital you are needing
     **********************************************/
    loadExistingHospital(id) {

        var hospitalQuery = new breeze.EntityQuery().from('Hospitals')
            .where('HospitalId', '==', id)
            .select('Organization.Name', 'Organization.Url', 'Organization.IsActive', 'IsPending');

        return createEntityManager()
            .then(em => em.executeQuery(hospitalQuery))
            .then(queryResult => {
                return {
                    entity: queryResult.results[0],
                    entityManager: queryResult.entityManager
                };
            })
            .catch(error => {
                alert('error on Load by Id');
            });

    }

    /**********************************************
     * loadHospitalList - loads all hospitals from this list.
     **********************************************/
    loadHospitalList() {

        var hospitalQuery = new breeze.EntityQuery().from('Hospitals');
            //.select('Organization.Name', 'Organization.Url', 'Organization.IsActive', 'IsPending')
            //.orderBy('Organization.Name');

        return createEntityManager()
            .then(em => em.executeQuery(hospitalQuery))
            .then(queryResult => {
                return {
                    entity: queryResult.results,
                    entityManager: queryResult.entityManager
                };
            })
            .catch(error => {
                alert('error on Load List');
            });


    }


}

I have the plugin being instantiated from my main.js file:

import {LogManager} from 'aurelia-framework';
import {ConsoleAppender} from 'aurelia-logging-console';
import {ConventionalViewStrategy} from 'aurelia-framework';
import {Configure} from 'aurelia-configuration';

LogManager.addAppender(new ConsoleAppender());
LogManager.setLevel(LogManager.logLevel.debug);

export function configure(aurelia) {

    aurelia.use
        .standardConfiguration()
        .developmentLogging()
        .plugin('aurelia-configuration',
            config => {
                config.setCascadeMode(false);
                config.setEnvironments({
                    Code: ['localhost'],
                    Dev: ['zzzzzzzzzz'],
                    QA: ['yyyyyyyyy'],
                    Prod: ['xxxxxxxxxx']
                });
                config.setDirectory('CeApps/configs');
                config.setConfig('config.json');
            })
        .plugin('aurelia-kendoui-bridge', (kendo) => kendo.pro())
        .plugin('aurelia-breeze');   // install the aurelia-breeze integration plugin.
    ;

    aurelia.start().then(a => a.setRoot('CeApp/app'));

}

I must be missing something - any thoughts??

Support for Typescript

Any chance for a simple typescript definition file for this?

I am trying to use it in a visual studio project that compiles with typescript. When I do this:

 import {ErrorRenderer} from 'aurelia-breeze';

I get an error of:

 Cannot find module 'aureila-breeze'

I can import other framework stuff:

 import {Container, autoinject} from 'aurelia-framework'

This works fine (and seems like a similar example to 'aurelia-breeze'.

However if I exclude aurelia-framework.d.ts from my project then it gives a similar error:

 Cannot find module 'aurelia-framework'

And when I put aurelia-framework.d.ts back in, that error goes away.

So this leads me to believe that I need an aurelia-breeze.d.ts.

I would make my own, but the setup with index.js as the core of the exports for the project is confusing me. (I am new to typescript and javascript so I may be in over my head a bit.)

Support for the webpack skeleton

I have an app built using the webpack skeleton. I tried:

npm install aurelia-breeze

Everything seems to have come down except that there is no module 'breeze' rather a module 'breeze-client'

When I try to bundle with webpack I get a bunch of errors of this type:

Module not found: Error: Cannot resolve module 'breeze'

from the aurelia-breeze source.

Just one breeze propertyChanged handler per bound entity?

Caveat: everything I say here is based on my reading the code, not executing it. I could easily have misread something and I invite you to correct me.

It appears that you are adding a new subscription to each entity’s entityAspect.propertyChanged event for every data bound property. That works. But will it scale? If we bind to 1000 entities each with 10 bound properties, that’s 10,000 event handlers.

I think we can get it down to one handler per entity.

Proposal

Imagine for each observed entity you have a BreezeObjectObserver (AKA boo) ... as you do now. The boo has a dictionary (a hash) of {propertyName, callbacks} where the callbacks are the Aurelia listeners; let's call that thing watches.

For efficiency we also keep a count of the number of subscriptions in the dictionary; call this subscriptionCount.

When Aurelia asks for a property observer, we get or create the new BreezeObjectObserver.

Then we add a property to boo.watches (if necessary) and add to its array of callbacks (which will have one element the first time). we bump the boo.subscriptionCount by 1. We return the unsubscribe function … as you do.

The first time we create a boo, we register a SINGLE breeze propertyChanged handler to entityAspect.propertyChanged.

Because breeze raises the changed event by property name, it’s trivial for that handler to find the watch for that property and get its array of callbacks: boo.watches[propertyName]. Pretty much the logic you have.

Unsubscribe is a matter of calling the unsubscribe function (as you do) and decrementing the boo.propertyCount.

Or perhaps setting the slot in the array to null instead! Jay found that it is significantly faster to stick nulls in an array rather than keep expanding and shrinking it. That repeated restructuring can force a lot of garbage collection apparently. It’s a little more work to fill with nulls and watch for nulls but he found it worthwhile. See the implementation of the Breeze EntityGroup. This is a refinement to be sure and not critical to the proposal.

When the boo.propertyCount === 0, we know we can unsubscribe from entityAspect.propertyChanged.

I think I would also discard the boo (object.entityAspect.__breezeObserver__ = undefined).

We'd have to harden the unsubscribe function against the risk that it was associated with a boo that no longer exists ... or is no longer valid. I don't think that's hard.

That is a refinement. You could always keep it and re-subscribe when the count === 1.

Guarding against detach and EntityManager clearing

Currently you allow Aurelia to continue binding to detached entities.

Why? In theory, one shouldn't be displaying a detached entity and there is no good reason to care about subsequent changes to a detached entity. You might as well unsubscribe.

I realize that Breeze still raises propertyChanged when you set the property of a detached entity. Do we care?

If we don't care, we should discard the BreezeObservableObject (boo) when the entity becomes detached.

When are entities detached?

An entity can become detached for a number of reasons.

  • you detach it programmatically
  • you deleted an unsaved new entity
  • you called rejectChanges on an unsaved new entity
  • after a successful save of an entity marked for delete
  • after clearing the EntityManager

What if we re-attach a detached entity?

Hmmm. If a view is bound to entity "x" . You detach it by one of the mechanisms just described. Then somehow you re-attached it behind the scenes without ever changing its view binding?

I'm not sure what happens. Aurelia probably thinks that the object's bound properties are observable and will be waiting for those callbacks to fire.

I personally don't think this scenario makes practical sense. You shouldn't put the user in this situation anyway. When an entity is detached it should be removed from view.

But I'm open to a counter argument.

Performance: splice or null?

Hi Jeremy

I looked again at the code. I think it is much better. Again, I'm only reading it but it seems much improved to me.

I had a lingering question about whether it is "better" to modify the subscription callback arrays during unsubscribe or to set the array slot with null and then fill the null holes with the next subscription.

I wrote a gist to test both ways of doing it, jacked up the iteration counts, and looked at it in the chrome profiler.

If I'm doing it right, the set-and-fill-with-nulls approach is faster. Not crazy faster but faster. For example, in one set of runs (alternating slice and null version trials three times), the slice approach took 6 seconds while the null approach took 5 seconds.

Each trial:

  • adds a subscription to a property named "first"
  • does the following 1,000,000 times:
    • adds a subscription for property X
    • simulates raising a property changed event (by calling observer.subscription).
    • removes that property subscription
  • removes the "first" subscription so that the observer's subscribe event simulation is cleared

Is that significant? Probably not in the grand scheme of things. But Jay did it this way in breeze so maybe we should do it here too. Your call.

btw, I followed the profiling instructions here.

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.