1
votes

I have a form where I am previewing a video youtube before posting it off. I am also using Reactive forms.

I need to be able to let the user preview their video before posting if off and currently, I am using ngModel for this to work.

<iframe *ngIf="video_url; else preview"
   [src]="'https://www.youtube.com/embed/' + video_url | safe: 'resourceUrl'" frameborder="0" .allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"allowfullscreen></iframe>
    <ng-template #preview>
      <div class="preview">
        <span>
         <p><i class="fab fa-youtube"></i></p>
         <p><small>Preview Your Youtube Video Here</small></p>
        </span>
      </div>
    </ng-template>
 <input type="text" 
        formControlName="video_url" id="video_url" 
        [(ngModel)]="video_url"
        placeholder="Add your Video ID here e.g: https://youtube.com/This_Is_Your_Video_ID"
 >

I know this isn't best practice as I am now getting these warnings in the console:

It looks like you're using ngModel on the same form field as formControlName. Support for using the ngModel input property and ngModelChange event with reactive form directives has been deprecated in Angular v6 and will be removed in Angular v7.

What is the best way to 'model' existing or new values in forms with Reactive Forms onchange($event)? Or is there a better technique for this?

I say existing and new, as when the form is in edit state, I need to also model the existing video_url which is found at article.video_url. Currently, this works for one approach only and not both existing and new values.

2
The point of reactive forms is to use FormControls instead of ngModel. That's why it does not make sense to use both formControlName and ngModel. The easiest way to create a FormControl is to use const myFormControl = new FormControl() on ts side and assigning it via <input type="text" [formControl]="myFormControl">. Then you can subscribe to myFromControl.valueChanges() which is an Observable.Arnaud Denoyelle
Thank you Arnaud, this will also accommodate for new and existing video_url values?Apex
I don't understand the question. The input value is actually 2-way databinded to myFormControl.value. Hope it helps.Arnaud Denoyelle
thanks, Arnaud a great help! I've taken a little from both to get the necessary outcome. Your help has really cleared up formControl for me. I was looking at it the wrong way and now I understand. thank you.Apex

2 Answers

2
votes

Could be wrong, but it seems like you're asking how to set the value of a form control.

it generally will look something like this:

this.form.setValue({video_url: this.video_url})

where form is your group with a control keyed under "video_url". you can set as many group values as you want like that, there is also patchValue() which will patch the form value fed in rather than set the whole thing, or you could set a single control like this:

this.form.get('video_url').setValue(this.video_url)

When and where you set that value kind of depends on where and where this.video_url gets set, so it's hard to say with any certainty without knowing more about your component controller. but the usual suspects are in data subscriptions or in the onInit life cycle hook or an input setter in the case of an input.

Knowing when your form value changes is simple, since every form control or group exposes a valueChanges observable:

this.form.valueChanges.subscribe(newValue => console.log(newValue))

this will emit on every value change within the form group, but as above, you can also subscribe to a single controls valueChanges stream which will only emit when that control changes.

0
votes

So thanks to the comments above, I have got the right solution. I will place my code here if anyone needs to solve this problem in the future.

so I have set the valueChanges event inside of the editArticle method like so:

editArticle(article: Article) {

this.articleEdit.get('video_url').valueChanges.forEach(
  (video_link) => {
    article.video_url = video_link;
    console.log(article.video_url);
  }
)

editArticle(article: Article) {

this.articleEdit.get('video_url').valueChanges.forEach(
  (video_link) => {
    article.video_url = video_link;
    console.log(article.video_url);
  }
)

this.articleEdit.patchValue(
  {
    feed_type: article.feed_type.data.id,
    title: article.title,
    sub_title: article.sub_title,
    description: article.description,
    text_content: article.text_content,
    author_name: article.author_name,
    author_avatar: article.author_avatar.data,
    video_url: article.video_url,
    header_image: article.header_image ? article.header_image.data : null,
    featured_image: article.featured_image.data,
    twitter: article.twitter,
    facebook: article.facebook,
    instagram: article.instagram,
    advertising_banner: article.advertising_banner.data,
    ad_link: article.ad_link
  });
}

this then listens for changes on the input field and logs it as the new value for video_url, but also previews the video URL in the view correctly:

a small slice of the form, which is relevent to the question:

<input type="text" formControlName="video_url" id="video_url"
 placeholder="Add your Video ID here e.g: https://youtube.com/This_Is_Your_Video_ID">
   <iframe *ngIf="article.video_url; else preview"
    [src]="'https://www.youtube.com/embed/' + article.video_url | safe: 'resourceUrl'" frameborder="0"
    allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
   <ng-template #preview>
       <div class="preview">
           <span>
             <p><i class="fab fa-youtube"></i></p>
             <p><small>Preview Your Youtube Video Here</small></p>
           </span>
       </div>
   </ng-template>

no more need for ngModel on the forms when using Reactive Forms!!! :)