pjlamb12
pjlamb12

Reputation: 2422

Angular TemplateRefs and Undefined Class Variables

I'm trying to use TemplateRefs in my Angular component so that the user of the package can get the benefit of the component but define the styles on their own. This is a good example of what I'm talking about. The component I'm working on is this one, from the angular-tag-select package. It takes a list of potential "tags" and allows the user to select certain ones from the list. Currently, you're limited to the default styles, and you have to pass in all the link classes, and it's really hard to overwrite the styles. By using ng-template and TemplateRef, you could get all the benefits of the tag select, with the logic being taken care of in the TagSelect component but you get to decide the layout.

I think I've gotten a good start on it, by adding the following to the TagSelect component:

<ng-container *ngTemplateOutlet="layoutTemplate; context: ctx"></ng-container>

The ctx variable for the context is the following:

public ctx: any = {
  tagsSelectedAtStart: this.tagsSelectedAtStart,
  tagsToSelect: this.tagsToSelect,
  tagMapping: this.tagMapping,
  tagItemIdentifierPlural: this.tagItemIdentiferPlural,
  canDynamicallyAdd: this.canDynamicallyAdd,
  possibleTags: this.possibleTags,
  selectedTags: this.selectedTags,
  filterText: this.filterText,
  filteredTagsLength: this.filteredTagsLength,
  fns: { 
    toggleTag: this.toggleTag
  }
}

I'm basically putting all the @Input variables and local class variables for the component on the context object. I'll go through and clean that out as I figure out what exactly needs to be there and doesn't need to be there.

One of the inputs on the TagSelect component is a list of possible tags that can be selected. I have provided an array of possible tags to select, and while I can confirm that it is passed in to the component, it's not output to the parent component to list out on the screen. If I pre-populate the possible tags list inside the TagSelect component with an item, then I can see those pre-populated items, but not the ones that are passed in, in the parent component. Also, when toggling a tag in the parent component, there is an error because the array that we save the selected tags to is undefined. But that array is defaulted to an empty array on component initialization.

It's like the component is initialized, but then the state of all the class variables is lost; I don't know how else to explain it.

I know this is probably really confusing, but I'm testing this functionality on StackBlitz here. If you have any questions that I can clear up, let me know, but that's the point I'm stuck at as of now.

Upvotes: 1

Views: 278

Answers (1)

Isaac
Isaac

Reputation: 2223

Here's what you needed:

toggleTag = (tag: Tag) => {

You were using:

toggleTag(tag: Tag) {

The problem is that when you pass the toggleTag function into your ctx object, this is no longer bound to the TagSelectComponent. Using an arrow function automatically binds this for you.

Here's a modified stackblitz.

EDIT:

You also need to update your ctx property any time the values change. I added an updateContext() function and call it at the end of ngOnChanges. You could do some performance tuning to only call it when specific inputs change.

Upvotes: 2

Related Questions