11

Following the guide from the Angular2 site I have this html:

<input #something (keyup)="doneTyping($event)">
<button (click)="add(something .value)">Add</button>

with this controller:

@Component({
  selector: 'my-app',
  appInjector: [SomeService]
})
@View({
  templateUrl: 'index-angular',
  directives:[NgFor]
})
class MyAppComponent {
  name: string;
  stuff: Array<string>;

  constructor(someService: SomeService) {
    this.name = 'Angular2Sample';
    this.stuff= someService.getStuff();
  }
  add(st: string){
    this.stuff.push(st);
  }
  doneTyping($event) {
    if($event.which === 13) {
      this.stuff.push($event.target.value);
      $event.target.value = null;
    }
  }
}

When the user hits enter in the input, the doneTyping method clears the input with $event.target.value = null;.

However I can't come with a way of doing the same after pushing the button.

codependent
  • 23,193
  • 31
  • 166
  • 308

6 Answers6

22

You can pass the input as a parameter in the button

<input #something (keyup)="doneTyping($event)">

<!-- Input as paramter -->
<button (click)="add(something)">Add</button>

And later in the add function

add(st: HTMLInputElement){
    this.stuff.push(st.value);
    st.value = null;
  }
Eric Martinez
  • 31,277
  • 9
  • 92
  • 91
5

Also, you usually want to avoid interacting with DOM as much as possible. I just checked the Todo app example on the angular2 github and they also access the DOM element, but the last real commit is 2 months old.

If you use data binding you can have a cleaner code which would result in something like :

<input [value]="_newStuff" (keyup.enter)="addStuff()">
<button (click)="addStuff()">Add</button>

Then in your class you can just define the member _newStuff : string, that you can implement addStuff as follow :

addStuff() {
    this.stuff.push(_newStuff);
    this._newstuff = '';
}

In most cases you might want _newStuff to be a model object that works as an interface like this :

class Stuff {
    id : any;
    property : any;
    otherProperty : any;
}

And then your _newStuff would be _newStuff : Stuff; and you could map it like this : <input [value]="_newStuff.property" (keyup.enter)="addStuff()">.

I know your sample code is very simple and you just try to get it to work, but I believe the data binding way is more in the logic of the framework, and the Form API basically gives tools such as Control, ControlGroup and FormBuilder that help you map your model on your view with Validators and such. It would be too cumbersome on something a bit larger to access the DOM everytime you need to change the view. In the end your example is almost raw javascript executed in an Angular2 context.

Coming back to your example, now imagine you have another event that triggers a new stuff to be added, say a double click or so, you'd need to add another method that handles this event, passing it again the HTMLInputElement, and do basically the same thing as you do on the keyup event handler, thus duplicating code again. With data binding your component owns the state of the view and you can therefore have one simple method that won't be affected by what kind of event triggered it. There you can do the test if the model is valid ( even though for this you'd use the Form API then ).

Anyways, I know this has been answered already, but I thought I would just help to improve the solution given my current understanding of it and how it could be applied to real cases.

Arnaud Boeglin
  • 763
  • 6
  • 12
  • Hi there! I was testing your and Gabor suggestion, which obviously is way better than coupling with the DOM. However I get this error when using [value] `[SyntaxError: Assigning to rvalue (156:52)]`... – codependent Aug 17 '15 at 07:07
  • Upvoted for the `(keyup.enter)`. Didn't know it was possible. Love it. – AlikElzin-kilaka Aug 22 '15 at 11:48
2

You can use a one-direction bindings to access the value of the input. This is a very clear architecture; you don't have to pass DOM elements to the controller.

Template:

<!-- controller.value -> input.value binding-->
<input #myinput [value]=myValue>
<button (click)="done(myinput.value)">Add</button>

Controller:

myValue: string; // If you change this then the bound input.value will also change

// be sure to import ngOnInit from @angular/common
ngOnInit() {
    this.myValue = "";
}

done(newValue) {
    // ... processing newValue
    this.myValue = ""; // Clear the input
}
Gábor Imre
  • 5,899
  • 2
  • 35
  • 48
  • The problem with this approach is that it bypasses the ngForm validity checkers and so your if your input was marked ng-invalid, it will still be invalid even though it now has a null value. – rmcsharry Jan 13 '17 at 00:32
0

Here's a good way to actually get your input objects to manipulate

Just need to import ViewChild from @angular/core

Template:

<input #something (keyup)="doneTyping($event)">

Class:

@ViewChild("something") something : HTMLInputElement;

doneTyping(e : KeyboardEvent) {
    var text = this.something.value;
    if (text != "") {
        //DO SOME STUFF!!!!
    }
}
Ben Perry
  • 1
  • 3
0

Since version 2 of Angular is old now, and we developers are in need much more trend solutions and but we may look old topics in order to find solutions here, I felt I should mention an answer from another topic similar to this.

That answer works and solved my problem in Angular 7 with Type Script. Here its link

There are two ways: 1) I it is created with var or let or const, then it cannot be deleted at all. Example:

var g_a = 1; //create with var, g_a is a variable 
delete g_a; //return false
console.log(g_a); //g_a is still 1

2) If it is created without var, then it can be deleted.. as follows:

declaration:

selectedRow: any; 
selectRowOfBankForCurrentCustomer(row: any) {
    this.selectedRow = row; // 'row' object is assigned.
}

deleting:

resetData(){
   delete this.selectedRow; // true
   console.log(this.selectedRow) // this is error because the variable deleted, not its content!!
}
LuDeveloper
  • 618
  • 6
  • 12
-2

A quick way to do it:

<input #something (keyup)="doneTyping($event)">
<button (click)="add(something.value);something.value=''">Add</button>

A more Angular way to do it:

HTML:

<input [(ngModel)]="intermediateValue">
<button (click)="add()">Add</button>

Controller:

intermediateValue: string;

add() {
    this.doStuff(this.intermediateValue);
    this.intermediateValue= "";
}
icer
  • 116
  • 3