0

I'm trying to update the value which is an input of Angular component by clicking on button which not a part of the Angular Element. How can I update the value in the Angular Elements in order to display in the UI?

HTML Code

<second-hello test="First Value"></second-hello> // This is a Web Component by Angular
<button onclick="change()">Change</button> // This button is part of the Vanilla JS Application. This is not a part of the Angular Component

JavaScript Code:

function change() {
 console.log(document.querySelector('second-hello').getAttribute('test'));
 document.querySelector('second-hello').setAttribute('test', 'New Test worked');
 console.log(document.querySelector('second-hello').getAttribute('test'));
}

// Above JS function changes the value and that can be seen in browser console but it does not update in UI
Ish Bhatt
  • 31
  • 6
  • 1
    Could you please post the full code, for both html and typescript ? – Mozart Aug 16 '19 at 17:53
  • Yes Sure @MozartAlKhateeb. I just noticed it – Ish Bhatt Aug 16 '19 at 17:54
  • So what do you want to do ? is it changing the value of second-hello to something else on click ? btw second-hello is not an angular component – Mozart Aug 16 '19 at 17:59
  • I want to change the value of attribute ```test``` of `````` element. The second-hello is an angular element So when change() function triggers, It updates the value of test from 'First Value' to 'New Test Worked' and the same can be seen in browser console (line 4 of function). But it does not update the value in the element itself. UI still displays First Value – Ish Bhatt Aug 16 '19 at 18:02
  • 1
    I think you are not using angular way of updating bindings – Naga Sai A Aug 16 '19 at 18:06
  • As you seem to really not want to go for an angular solution you might try to hack something together with ngAfterViewChecked: https://angular.io/api/core/AfterViewChecked – Michelangelo Aug 16 '19 at 18:33
  • Everybody missed the plot here! The guy is talking about ANGULAR ELEMENTS (https://angular.io/guide/elements), which are Web Components to use with plain old javascript pages. He's asking about how to trigger change detection within the Angular Element/Web Component when an input is changed *from the plain javascript page*, which is a normal way of using it. (I'm stumbling on the problem myself at this very moment). – Bob Sep 27 '19 at 12:44

3 Answers3

2

Your javascript code is trying to directly manipulate the DOM. That is a very jQuery like way to do things, but this is not really the way to leverage and use Angular.

In principle, you want to use ng-model to bind data to your angular component and your function would work with the variables that are bound to this ng-model in your controller. Note: it doesn't have to be ng-model, but this is a great example of how to map the data.

Example:

// in component/page
<my-component ng-model="testData"></my-component>
<button (click)=changeData('value')></button>

// in controller
this.testData = "Initial value"

changeData(newData) {
    this.testData = newData;
}

You should spend some time working with the Angular tutorials (https://angular.io/start/data) which will model how to work with components and change their values.

tarik
  • 312
  • 1
  • 9
  • I understand your approach and it totally makes sense. Here in my scenario, the button is not a part of the angular template. I'm using Web Component `````` in the Vanilla JS application. The button is part of the Vanilla JS Application which is updating the value of the attribute which is an ```@Input``` of Angular component. – Ish Bhatt Aug 16 '19 at 18:15
  • I guess to try and do what you want, you can look at the generated HTML, but if you want to manipulate data in an Angular component, you should make your button a part of the controller for the page. If you want to directly manipulate the DOM, you should consider not using Angular at all. When interacting with Angular components, you need to speak Angular's language. Since this is all ultimately javascript in the browser, yes, you could actually find a way to go around it, but then your application is likely to break when Angular tweaks how it interacts with the DOM. – tarik Aug 16 '19 at 18:25
  • 1
    This answer is not relevant to the question. @IshBhatt is talking about communication between plain old javascript page and Angular Element/Web Component (not between Angular Components). – Bob Sep 27 '19 at 12:45
  • @bob, the point of my answer is that other than perhaps some kind of screen scraper code from OUTSIDE the current page, you really do not want to write code outside the Angular ecosystem that tries to manipulate data inside the Angular ecosystem. – tarik Sep 30 '19 at 21:24
0

From Angular we need take account two things: one, how refered to the object window, the another one is that we need use ngZone to tell Angular that a change happens. You can has something like

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ],
  providers:[{provide:"windowObject", useValue: window}]
})

export class AppComponent  {
  name="Angular"
  constructor(@Inject("windowObject") private window: Window,private zone: NgZone){
    this.window["setData"]=(value:any)=>{
      this.zone.run(()=>{
      this.name=value
      })
    }
  }
}

See how you inject the object window and how defined a function "setData" in window. The you can call to the function outside in a button in java script

<button onclick="window.setData('Angular Renamed')">button</button>

You can see in stackblitz

NOTE: you can improve this idea creating a service that emit a value, so all your component that subscribe to the subject take account this changes

Eliseo
  • 50,109
  • 4
  • 29
  • 67
0

You can change the properties (input) of a web component , Angular will then run its onChanges cycle and you can implement the behavior you want from the new value.

HTML

 <my-component size="5"></my-component>

Plain javascript (source page)

const wc = document.getElementsByTagName('my-component')[0]
wc.size = 10

Your Angular component

ngOnChanges(changes: SimpleChanges): void {
  console.log(changes.size)
}

FlowP
  • 11
  • 3