Angular2 function call from html element with no load event (or similiar) - html

I am new to Angular and have run into a problem that seems to have a javascript work around but they aren't very elegant.
I have a model with an array property. I ngfor the list property to build some html selection options. This is all working nicely. The problem comes when I am trying to set default value...the html elements don't have a load event.
I tried numerous html elements and they don't appear to have a load event either but I certainly could be doing it wrong.
I have seen a solution to put javascript tag right after the html and I could do that but I was really looking for a more elegant way in Angular.
I saw this SO post and thought that was my answer but there is a warning given that I agree with and thus it doesn't appear to be a good solution.
Regardless I tried it just to see if it would work and I got:
Failed to execute 'setAttribute' on 'Element': '{{loadDefaults()}}' is not a valid attribute name
<span {{loadDefaults()}} ></span>
So how can I fire an AS2 function in the component to load the default values?
HTML (btw this is NOT a full page load so there is no body tag):
<tr>
<td *ngFor="let loc of locOptions;">
<span>{{loc.text}}</span>
<input type="radio" name="radiogroup" [value]="loc.value" (change)="onSelectionChange(loc.value)">
</td>
</tr>
Edit
I thought perhaps mistakenly that ngoninit would fire too soon...before the html elements are rendered.
So perhaps what is being suggested is that I add a boolean is default to the model and bind THAT as the element is rendered.

In your ngonit function set this.locOptions to your default values. The value can be changed later on in any function and the change will be reflected in the view. Hope this helps you.

You should use ngOnInit to init you data, and call retrieve your data from your component :
defaults : any;
ngOnInit {
this.defaults = loadDefaults();
}
loadDefaults() {
//get data
}
HTML :
<span>{{defaults}}</span>

Related

Angular html custom element from typescript [duplicate]

I'm setting HTML returned from the API in my Angular component:
<div [innerHTML]="content"></div>
content in this example is something like this:
<table>
<tr>
<td>[audioPlayer:file.mp3]</td>
</tr>
</table>
Now I would like to inject the actual component inside the table cell.
If I make a certain container, I can create the component with createComponent:
audioPlayerComponentRef: ComponentRef<AudioPlayerComponent>;
#ViewChild('placeholder', { read: ViewContainerRef }) container;
const factory: ComponentFactory<AudioPlayerComponent> =
this.componentFactoryResolver.resolveComponentFactory(AudioPlayerComponent);
this.audioPlayerComponentRef = this.container.createComponent(factory);
Then I can inject it into a container in the template:
<div #placeholder></div>
However, going back to my original goal, I can't use such a container, as the component needs to be injected into a specific position into an innerHtml block.
I've been brainstorming all day, but I can't see any way to achieve this.
Generally speaking, this is contrary to the way Angular works. [innerHTML] is not parsed for any Angular functionality. No component selectors or even a ViewContainerRef can be found there. Rather, even remotely suspicious HTML, CSS and JS is removed as a security measure as Angular only trusts its own templates.
So InnerHTML is a no-go. But I was in the same boat myself and have written a library to solve this exact problem. With it, you can freely load dynamic components into strings without compromising security. If you're still stuck on this, you might wanna have a look at it.

Pairing or Connecting input and button elements with angular

I was following the tutorial Tour of Heroes. While adding a new hero they say
You can use an element paired with an add button.
Insert the following into the HeroesComponent template, after the heading:
<div>
<label for="new-hero">Hero name: </label>
<input id="new-hero" #heroName />
<!-- (click) passes input value to add() and then clears the input -->
<button type="button" class="add-button" (click)="add(heroName.value); heroName.value=''">
Add hero
</button>
</div>
Here I don't understand what is #heroName inside in input element (what is it called) and how does it help in pairing that input element with the button element.
Basically, what is that #<keyword> syntax within that input element. I know that it is not the id as that is already declared.
To answer the question, it's a reference to the input. You can find more details here:
https://angular.io/guide/template-reference-variables
Template variables help you use data from one part of a template in
another part of the template. Use template variables to perform tasks
such as respond to user input or finely tune your application's forms.
In the tutorial context, it's a reference to the input element. It helps to pair it with a button to be able to access it's value, without having to actually define a variable in the component.ts and trying to update the template directly. This help you "skip" a step, and actually have direct access to that value.
Template reference variables can become very handy in certain cases and are commonly used for example in angular material ( to call a function for a component )
<mat-menu #menuComponent ...></mat-menu>
<button (click)="menuComponent.close()"></button>
In the above example, you bind the menuComponent variable to "mat-menu" component, in which case you can access all the variables, public methods of such. In that case we can call "close" method from the mat-menu component.
Let me know if this is still unclear and I can try to give you more examples and explanation

Angular 4 innerHTML removes directive from the element

I am trying to set innerHTML in a div but the directive used in the text is ignored. I am not sure if it is a invalid attribute(according to HTML) So below is my code:
<table class="table">
<tbody>
<tr>
<td>
<div [innerHTML]="issue.longText"></div>
</td>
</tr>
</tbody>
</table>
the value of issue.longText in component.ts is:
<ul><li>20/07/2018 - Hello!This is the test issue on click on it(<span [issueOpener]='{"recordId": 4, "page":1}'>link</span>)</li></ul>
And when I inspect the div I've got the following:
<ul><li>20/07/2018 - Hello!This is the test issue on click on it(<span>link</span>)</li></ul>
Directive issueOpener is removed from the span. So how can I prevent this directive? Any help would be greatly appreciated.
This is wanted behavior and here is why : when you write Typescript code, you aren't writing your final application. Your code needs to be compiled first.
To be compiled, your code goes through a process ran by the CLI : during this process, the compiler replaces every piece of Angular code with valid JS code.
This means for instance, that (click) event become onclick (This one's not entirely true, but that pictures the point I'm making).
When you use innerHtml, you write final code : it won't be compiled. It's not Angualr code, so it won't work like you hoped.
Ajay you can do one thing and that will surely work in your case.
Please refer following link:-
Angular 5 - How to call a function when HTML element is created with *ngFor
You can write logic on ngAfterViewInit() that should be responsible for adding directive at the HTML which is now loaded so that directive can be added dynamically.
Refer:-
How to dynamically add a directive?

Angular2: undefined errors when trying to set focus to an input field using #ViewChild annotation

I have a input field which I set focus to when my view loads in the following way:
ngAfterViewInit() {
this.focusInput.nativeElement.focus();
}
this works fine from within the ngAfterViewInit() function but when I try to do it in another part of my view when a button is clicked I get an exception saying that focusInput is undefined. After reading up a bit it seems like ngIf could be the cause of this as the part of the view that contains the input field #focusInput gets shown or hidden using ngIf. Is there any way I can check using ngOnChanges() or anything else whether the #focusInput input field is currently shown and if it is set focus to it?
It happens when you have ngIf or ngFor directives inside your template and your input can not be linked to focusInput property you added inside your class. Instead use this code:
<input type="text" #myInput />
{{ myInput.focus() }}
Just add {{ myInput.focus() }} right after input inside template
The simplest solution turned out to be writing a custom focus attribute directive. This helped a lot:
How to move focus on form elements the Angular way
I know its very late to answer your question. If you want focus after any click or view change so for this you need to call change detector.
You can call change detection after your view change or a click by calling detectchanges().
`constructor(private detRef:ChangeDetectorRef) {}
#ViewChild('name_input') input: ElementRef;
private buttonClick(): void {
this.detRef.detectChanges();
this.input.nativeElement.focus();
}`
Hope this will helpful.

JQuery Validation Engine, doesn't live validate if i add a element after page was loaded?

at the moment i'm using this validation plugin: (http://www.position-absolute.com/articles/jquery-form-validator-because-form-validation-is-a-mess/)
but when it comes to the part of validating i have a problem.
If i want to be able to validate a element which doesn't exist from the beginning, it only validates it when i press submit. But i want to be able that the element gets a validation while especially the focus get lost. on a element which is there all the time i can type, focus lost, and it writes "something wrong" and disapear if i changed the value to anything correct. but if i do the same thing on a element which i added with the jquery append function, it won't do anything until i press submit.
anyone a simple solution for this. perhaps with the jquery .live function?
this is my script:
var use_ajax=true;
$.validationEngine.settings={};
$("#contact-form").validationEngine({
inlineValidation: true,
promptPosition: "centerRight",
success : function(){use_ajax=true},
failure : function(){use_ajax=false;}
})
and this is a sample of an element which get added by append:
<tr>
<td><label for="email">Nummer</label></td>
<td><input type="text" value="" id="nummer" name="nummer" class="validate[required]"></td>
<td> </td>
</tr>
The accepted answer i had first, won't work with this:
$("#contact-form").validationEngine({
ajaxSubmit: true,
ajaxSubmitFile: "submit.php",
ajaxSubmitMessage: "Contact saved succesful! <br> <img src=''/> <a href='test.php'>TestLink</a>",
ajaxSubmitExtraData: "contact=john",
success : false,
failure : function() {}
});
This is normal.
When you bind the validation to your inputs, bindings for focus, blur etc are bound to the inputs. when you add an input item, they are not bound.
To bind them to, call the validation binding again after you added new inputs.
It might be so that the elements that were bound, will get second bindings, so you might have to unbind the validator:
$.removeData($('#my_form_id'),'validator');
and then bind it again
$('#my_form_id').validate()
#Edit to release any binds on an object, you can do .unbind() this is for events tough. I think jqtransform works on a class selector ? like class="jqtransform", you can try to remove that class