Josiah
Josiah

Reputation: 3158

Angular2 Class not exposing functions

I have this model:

(function(app) {
  app.productLine =
    ng.core.Component({
      selector: 'product-line',
      templateUrl: 'templates/sales-product.html',
    })
    .Class({
      constructor: function() { 
          this.products = [new app.product('101010101010101', '1', '19.99')];
      },

      addLine: function() {
          this.products.push(new app.product('101010101010101', '1', '19.99'));
      }
    });

})(window.app || (window.app = {}));

(function(app) {
    app.product = function (upc, quantity, price) {
        this.upc = upc;
        this.quantity = quantity;
        this.price = price;
        return this;
    }   
})(window.app || (window.app = {}));

However, I can't figure out how to expose addLine() so I can call it elsewhere.

Logging productLine only shows the constructor:

console.log(app.productLine);
function app.productLine<.constructor()

And calling app.productLine.addLine() gives TypeError: app.productLine.addLine is not a function.

EDIT:

I found that adding the addLine function to app.productLine directly does work. Of course, then the scope of this is changed, so there needs to be a reference to the constructor's results in a more obvious location.

(function(app) {
  app.productLine =
    ng.core.Component({
      selector: 'product-line',
      templateUrl: 'templates/sales-product.html',
    })
    .Class({
        constructor: function () {
            this.products = [
                { upc: '', 
                  quantity: '', 
                  price: '' 
                }
            ];

            app.productLine.products = this.products;
        }
    });

  app.productLine.add = function (upc, quantity, price) {
        app.productLine.products.push({
            upc: upc,
            quantity: quantity,
            price: price
        });
  }

})(window.app || (window.app = {}));

You can then run app.productLine.add(123,456,789); and the model is updated.

The view, however, is not updated immediately. I believe it is necessary to trigger an update somehow, but with 2-way data binding, if you use the UI to update the model all of the updates appear.

Upvotes: 2

Views: 1330

Answers (2)

Michael Kang
Michael Kang

Reputation: 52867

If you want to expose a shared function that multiple components can use, I suggest implementing a Service and registering it with the application-level injector.

Demo Plnkr

Product Class and ProductService

var Product = ng.core.Class({
  constructor: function (upc, quantity, price) {
    this.upc = upc;
    this.quantity = quantity;
    this.price = price;
  }

});
var ProductService = ng.core.Class({
  constructor: function() {
     this.products = [new Product('101010101010101', '1', '19.99')];
  },

  addLine: function () {

      this.products.push(new Product('101010101010101', '1', '19.99'));
  }
});

Registering ProductService with the Application-Level Injector

(function(app) {
  document.addEventListener('DOMContentLoaded', function() {
    ng.platform.browser.bootstrap(app.AppComponent, [ProductService]);
  });
})(window.app || (window.app = {}));

Injecting ProductService in Component Constructor and Calling AddLine

(function(app) {
   app.AppComponent =
      ng.core.Component({
          selector: 'app',
          directives: [app.ProductLine],
          template: '<h1>Anguar 2</h1> <button (click)="addLine()">Add Line</button> <ul><li *ngFor="#product of service.products"><product-line [product]="product"></product-line></li></ul>'
      })
     .Class({
         constructor: [ProductService, function (service) {
            this.service = service;
         }],
         addLine: function () {
             this.service.addLine();
         }
     });
 })(window.app || (window.app = {}));

ProductLine directive with Product Input Binding

This directive is used by the parent component.

(function(app) {
    app.ProductLine =
      ng.core.Component({
          selector: 'product-line',
          inputs: ['product'],
          template: 'UPC:{{product.upc}}<br> Price:{{product.price}}<br>Qty:{{product.quantity}}',
      })
      .Class({
          constructor: function () {
          }
      });      
})(window.app || (window.app = {}));

ProductService is a singleton. Any component can inject the ProductService and call AddLine() and any component that binds to products will automatically get updated as part of the default change detection strategy.

Upvotes: 1

Poul Kruijt
Poul Kruijt

Reputation: 71961

Have you tried:

var productLine = new app.productLine();
productLine.addLine();

It seems to me that app.productLine is a class which should be instantiated.

Ah no.. scratch that.. app.productLine is a Component. Never mind me. I only know angular2 in typescript :). I don't think my solution will work, but you can always try. In typescript you don't instantiate components yourself. You just do that by putting them in a template (or using the dynamicLoader, or the Injector).

But like I said. I have no idea how to do it in your situation

Upvotes: 0

Related Questions