2

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.

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Wow, I hadn't even found inputs in the docs. I must have missed it. Glad I could help you break 15k - congrats!
0

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

5 Comments

I believe productLine is instantiated when the template is bootstrapped. But I'll check it.
Yes, you can instantiate it again, but it won't be the instance you were looking for :)
Exactly - that "works" in the sense that I don't get errors and I can "add lines" to the products[] array. But the model isn't bound to document at all, so it doesn't change anything (which is what I'm trying to accomplish). So I guess I want to know how to assign the instance I want to a variable.
You should inject the component into the component where you are trying to add the line, using dependency injection.. But good luck finding a javascript example..
I updated it somewhat by doing it how I would in ES5 sans Angular. You don't happen to know how to trigger a view update manually by any chance do you? I found some suggestions in the angular docs, more docs, and on a plunker but I couldn't get injection working.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.