I have a simple page with an input element that has a DOM event (input). The HTML page also calls a function that just outputs something via console.log. Now when I open the page, it will show the log, but when I type something into the input field, it will also trigger the function EVERY time I type something.. (Actually, when I type a letter, it will console.logs TWICE every time)
Why does this happen? How to prevent it? I read some things about changeDetection, but is there another solution?
HTML:
{{test()}}
<input class="input-msg" [value]="textValue" (input)="textValue = $event.target.value;">
.ts:
export class TestComponent implements OnInit {
constructor() {
}
test() {
console.log('test message');
}
}
Expected Behavior:
The {{test()}} should not be called when typing something into the input field
Since you're calling a function in one of the data-binding syntaxes, whenever Angular performs Change Detection, it will call this method.
Before for a function, anything that cases is the value that it returns. And for Angular to know that the returned value has changed, Angular will have to run it.
This is the exact same issue that people have raised a several questions here:
Angular: Prevent DomSanizer from updating on DOM Events
Angular performance: ngStyle recalculates on each click on random input
Angular 7 ,Reactive Form slow response when has large data
You might want to read through these threads to understand what's going on here and how you can fix this issue.
The solution is to basically design your implementation in such a way, that it never calls a method in one of the data-binding syntaxes, i.e.
In String Interpolation - {{ methodCall() }}
In Property Binding - [propertyName]="methodCall()"
In Attribute Binding - [class.className]="methodCall()" / [style.style-name]="methodCall()"
An alternative solution is do move this code to a Child Component and configure the changeDetectionStrategy on that child component to ChangeDetectionStrategy.OnPush
Related
I have a angular template which contains a ng-template. I have tried to insert an embedded view via ngTemplateOutlet. However I always get the following error:
core.js:4061 ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: '[object Object]'.
This is the part where I am trying to use ngTemplateOutlet
<ng-template [ngTemplateOutlet]="headerLogoMiniComponent?.templateRef"></ng-template>
If i remove this line, the error will fix. What should I do to solve this problem without remove the mentioned part?
I suppose that I should add a condition with *ngIf for that wait headerLogoMiniComponent to be loaded. (But I don't know how to do that)
The declaration looks like the following:
#Component({
selector: 'mk-layout-header-logo-mini',
template: '<ng-template #templateRef><ng-content></ng-content></ng-template>'
})
export class HeaderLogoMiniComponent {
#ViewChild('templateRef',{static: false}) public templateRef:TemplateRef<any>; }
#ContentChild(HeaderLogoMiniComponent, {static: false}) public headerLogoMiniComponent: HeaderLogoMiniComponent;
Probably you have to check the Angular lifecycle hooks.
ngOnChanges()
Called before ngOnInit() and whenever one or more data-bound input properties change.
Respond when Angular sets or resets data-bound input properties.
The method receives a SimpleChanges object of current and previous property values.
Note that this happens very frequently, so any operation you perform here impacts performance significantly.
ngOnInit()
Called once, after the first ngOnChanges().
Initialize the directive or component after Angular first displays the data-bound properties and sets the directive or component's input properties.
ngDoCheck()
Called immediately after ngOnChanges() on every change detection run, and immediately after ngOnInit() on the first run.
Detect and act upon changes that Angular can't or won't detect on its own.
ngAfterContentInit()
Called once after the first ngDoCheck().
Respond after Angular projects external content into the component's view, or into the view that a directive is in.
ngAfterContentChecked()
Called after ngAfterContentInit() and every subsequent ngDoCheck().
Respond after Angular checks the content projected into the directive or component.
ngAfterViewInit()
Called once after the first ngAfterContentChecked().
Respond after Angular initializes the component's views and child views, or the view that contains the directive.
ngAfterViewChecked()
Called after the ngAfterViewInit() and every subsequent ngAfterContentChecked().
Respond after Angular checks the component's views and child views, or the view that contains the directive.
ngOnDestroy()
Called immediately before Angular destroys the directive or component.
Cleanup just before Angular destroys the directive or component. Unsubscribe Observables and detach event handlers to avoid memory leaks.
Visually something like this:
So you should put ViewChild assignment in ngAfterViewInit() and the ContentChild assignment you should put in ngAfterContentInit() lifecycle hook.
ngAfterContentInit() {
this.headerLogoMiniComponent = 'something';
}
ngAfterViewInit() {
this.templateRef = 'something';
}
First of all This is actually a warning rather than an error.
ExpressionChangedAfterItHasBeenCheckedError is thrown when an expression in your HTML has changed after Angular has checked it. In DevMode change detection adds an additional turn after every regular change detection run, to check if the model has changed. This error is only thrown in develop mode and it is often a sign that you should consider refactoring your code, as Angular warns you that this change in your expression will not be picked up when enabling production mode..!
One of the main root cause for this type of warnings is, you are executing some code in AfterViewInit which often happens when working with ViewChild, as it is undefined until AfterViewInit is called.
Check the below link for a detailed explanation and better understanding of ExpressionChangedAfterItHasBeenCheckedError..
ExpressionChangedAfterItHasBeenCheckedError Explained
Does in Blazor client app every event triggered (mouse, keyboard, touch,...) cause the whole UI refreshed?
In the below example, on every key input, i is incremented while it not bound to oninput event.
<input type="text" #bind-value="#name" #bind-value:event="oninput"/>
#name
#ComputeResult()
#code {
string name;
int i=0;
public double ComputeResult()
{
i = i + 1;
return i;
}
}
At the beginning, whenever you wanted to re-render your component, you had to call the StateHasChanged method which serves as the starting point of the rendering process. Nowadays, this is not necessary any longer. The StateHasChanged method is automatically called whenever a UI event, such as change or click is triggered. If you attach an empty event handler to a button control, and hit it, the StateHasChanged method is still called, which results in the re-rendering of your component, and consequently evaluating the expression #ComputeResult(). Note that this behavior can be altered by overriding the ComponentBase.ShouldRender method whose default returned value is true. Note that even if you overrides this method to return false, the first render always takes place.
Components are created only once, and they may be re-rendered multiple times. The re-rendering process and what is re-rendered is described in the answer by Kyle...
Only DOM elements that have changes get updated, not the entire UI. Blazor uses what they call a Render Tree to keep track of the elements that have changed and need to be updated. When an event fires, it regenerates the Render Tree and compares it to the old one to find changes, and then only updates the changed items in the render tree in the DOM.
Components render into an in-memory representation of the browser's Document Object Model (DOM) called a render tree, which is used to update the UI in a flexible and efficient way.
After the component is initially rendered, the component regenerates
its render tree in response to events. Blazor then compares the new
render tree against the previous one and applies any modifications to
the browser's Document Object Model (DOM).
From: https://learn.microsoft.com/en-us/aspnet/core/blazor/components?view=aspnetcore-3.1
I receive data in a function and this function needs to load a new page. I was doing this with Jquery using the method .load(), But my vue method gets an error saying that can not find the element in the other page.I believe that could be a better approach, but I do not know how I can pass data through a vue component
static foo(a,b){
$('#maindiv').load("/newPage");
new Vue({
el: '#newPageElem',
data: {
vueVar1:a
vueVar2:b
},
});
}
How can I do that? I believe that using Jquery is not the best way to achieve this, but I dont know how to change routes with vue and passing parameter between them.
Thanks.
You can take a look at vue-router here: http://router.vuejs.org/en/essentials/getting-started.html - it allows you to handle all the client-side routes.
For making http calls to receive data from server, you can use vue-resource (https://github.com/vuejs/vue-resource)
It is better to avoid mixing jQuery with Vue, as Vue is responsible for rendering the DOM. If you make any DOM changes with jQuery, it will get over-written by Vue in the next DOM update. So you will end up spending a lot of time in debugging.
Also, you cannot instantiate a Vue app inside a function, as seen in your code example, unless you call the function on page load. Ideally, the first few lines of script should start the Vue app.
When I google "Knockout Google Maps" I find quite some KO-based Google Maps implementations. All of which I was able to find take the approach to use a custom binding handler whereas I originally intended to implement it as a Knockout component.
Examples:
http://www.codeproject.com/Articles/351298/KnockoutJS-and-Google-Maps-binding
http://www.hoonzis.com/knockoutjs-and-google-maps-binding/
https://github.com/manuel-guilbault/knockout.google.maps
Can anyone point me in the right direction why one would prefer a custom binding handler over a KO component here?
My planned use case is this:
I'm implementing a page with a list of address search results. The list so far is a KO component, each list entry is generated by another KO component which the list component repeatedly calls in a foreach binding. Next to this list of search results I need a google map showing the result entries also in the map. There will also be quite a lot of interaction between the list, the list entries and the map.
Here's what I've got so far:
var GMap = function () {
var self = this;
var initMap = function() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 13,
center: {lat: 51.4387974, lng: 6.9922915}
});
};
initMap();
};
$(document).ready(function() {
ko.components.register('gmap', {
viewModel: GMap,
template: { element: 'gmap' }
});
ko.applyBindings();
});
#map {
height: 400px;
width: 600px;
}
<script src="https://maps.googleapis.com/maps/api/js?v=3.22"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<gmap></gmap>
<template id="gmap">
<div id="map"></div>
</template>
A component and a custom handler are completely different things.
Custom binding
Basically a custom binding have access to:
the HTML component where it's used
the bound value (expression supplied to the binding)
all the other bindings in the element
the binding context of the element, from which you can acces to $root, $parent, and so on
Its definition includes two functions:
init: that allows to do the initial setup, like initializing widgets, setting event handlers and so on
update: it's called after init. In that moment you can access properties (including observable properties) through the binding, all the element bindings, the context and so on. This creates subscriptios that will call update when any of the accessed observable changes.
So a custom binding shuld be used when you need to interact directly with the DOM element, for example to modify its properties, initialize widgets, subscribe to events and so on
Component
A component is completely different. When you define a componente you must define:
a template, which is a set of DOM elements, usually with bindings
a viewmodel (usually a constructor or a factory)
When you use the component:
the viewmodel is instanced
the template is loaded
the viewmodel is bound to the template
So, a componente allows to reuse viewmodels and templates
So, what's the difference?
A custom binding has direct access to the DOM elements, allowing to interact with them, subscribe to events, modify properties, and so on
A component is only a viewmodel, and a set of DOM elements with bindings to that particular viewmodel.
So, in the case of Google Maps, which needs to initialize a widget (the map) and interact with Map events, and respond to observable propèrties cahnges, you could never use a component, because the component doesn't allow the direct interaction with the DOM elements. (Remember is a bunch of HTML elements with bindings, and the corrresponding view model, whic can't include any logic to intercat with those elements).
A custom binding usually applies to a single element (althoug it could handle its children, like foreach). In the case of Google Maps you only need the element in which you'll show the map.
A component is usually a more or less complex set of DOM elements, which are not accesible "from the outside". The only communication with the main viewmodel is done through parameters. The component cannot directly interact with the DOM elements: it must do it via ko bindings.
So, for the case of Google Maps is clear that you need a custom binding.
It only makes sense to create a component when you want to modularize or reuse a set of DOM elements, and the related viewmodel, which can also include functionality like accessing web services (via AJAX), making computations (propbaly by using computed observables), and so on. For example, a shopping cart could be implemented using a component, which would include:
the DOM elements to show the items in the cart (probably an HTML table, and some controls)
controls to modify the cart content (for example for deleting elements, or changing quantities)
a viewmodel that show the total, the taxes and so on
functionality to store the cart for later, or pay for it (which could be ajax calls to services)
In this case the cart would have a viewmodel which would include the computed observables (to show the total and taxes), the functionality to remove items, or modify quantities, or store or pay, and so on. And a concrete set of DOM elements with bindings for this viewmodel, i.e. the HTML to show the cart and interact with it.
In the case of Google Maps a component could not be used without the help of a custom binding or with the hacky use of additional, non ko, scripts.
If you wanted to show a list of places beside a map, and modify that list, you could use a component, which would include a viewmodel with the list and related functionality, and a template including an element with the Google Maps custom binding. That would make sense: viewmodel + several elements.
Conclusion
This all means that a custom binding usually have a deep interaction with the bound DOM element, while a component has a higher level interaction with the elements, which must be done through bindings.
So, they play a role at a very different level. You cannot compare or interchange them.
If you insist on doing so, you could create a beast of a binding which behaves like a component, becasue you have full control on the elements, and full acces to the view model, but that's harder to implement than a component. And probably could do the other way round also in some esoteric way.
Binding
Binding, a custom or not, is a very simple concept that covers 2 things:
A property of a UI element changes, and thus it should update an object (ViewModel)
A property of the object (ViewModel) changes, and thus it should update the UI element.
From the above if only 1 implemented, it is called One Way Binding (because if you change the UI, it will update the object but not the other way around). If both 1 and 2 are implemented, it is called Two Way Binding.
So at any time if you think you need something to do that, you would need to use binding, custom binding if the framework does not have the binding you need.
Most likely, the maps you speak of needed something like above. And it actually did because the author says this in the first paragraph:
Concretely, you can learn how to make the maps marker part of the View and automatically change its position any time when the ViewModel behind changes.
See, the author talks about 2 above: When the ViewModel changes, change the position of UI element.
Component
A component is a concept of having a reusable item that may have a UI but not necessarily, and all the code needed to make it work packaged along with it. This way it can be reused. For example, it may simply be an input UI element that only allows numbers. All the code needed for it is packaged along with the UI element.
Now the code packaged along with it may code related to bindings. It may even have custom bindings if the framework they used did not have the binding they needed. In addition it may have additional code that has nothing to do with binding.
Furthermore, a component may have a single UI element or multiple. A good example of a component with multiple elements would be a message box.
In Conclusion
Bindings and Components are separate things. A component may have bindings within it or it may have other code to make it work or both.
In the case of the maps you speak of, they have only added a feature to it: To react to changes in the ViewModel. It is not a component because it is not self contained and reusable.
They could have done it using a component. However, if they did that and said it is a KO component, it may still have KO specific binding code packaged with it along with the ViewModel and all the UI elements needed.
I can get my <iron-meta> instance to work properly when using a static value. But when I bind the value to a dynamic variable (using {{}}) it <iron-meta> no longer behaves as expected.
Does <iron-meta> support binding its value to dynamic variables?
<iron-meta id="meta" key="info" value="foo/bar"></iron-meta> // works
<iron-meta id="meta" key="info" value="{{str}}"></iron-meta> // fails
Previous work
This question is a refinement of this question in order to clarify that the ONLY thing causing the problem is the change from a static string value to a dynamic string value binding. I was getting a lot of other suggesting that had nothing to do with the change from static to dynamic so I thought it might be best to rewrite the question to clarify that. But the entire code context is contained in the links there if that would help.
Alternative solutions
There has been some recent chatter about using <iron-localstorage>. Perhaps that is the best way to go for dynamic binding essentially creating global variables?
Yes, <iron-meta> does support binding to variables, but perhaps not in the way you think.
Example: http://plnkr.co/edit/QdNepDrg9b3eCTWF6oRO?p=preview
I looked through your code here, here, and here but I'm not entirely clear what your expectations are. Hopefully my attached repro might shed some light. I see you have declaratively bound <iron-meta id="meta" key="route" xvalue="foo-bar" value="{{route}}"></iron-meta> which is fine - when route changes, iron-meta's key="route" will update accordingly.
However, be aware that in Polymer 1.0, <iron-meta> is in essence a one-way bind from parent to child in the sense that you set a meta key value dynamically by binding to a property; but to get that value, you'll have to get it imperatively via iron-meta's byKey() method.
<iron-meta> is just a simple monostate pattern implementation without an in-built path notification mechanism. What this means is value changes do not propagate upwards. Therefore, doing something like
<!-- this does not work like the way you think -->
<iron-meta id="meta" key="foo" value="{{bar}}">
in order to get the value of foo, or listen to changes to foo, does not work. This behaves more like a setter, where you set the value of foo based on your data-bound property bar.
From what I gather, it seems that you're trying to implement some sort of global variable functionality. A monostate implementation used to work in Polymer 0.5, but not in 1.0. Unfortunately, until Google endorses a "best-practice" pattern for this, suggestions till-date seems a bit speculative to me. You might find this (Polymer 1.0 Global Variables) helpful.
I have had success using <iron-signals> to communicate global information. I know there is a warning in the <iron-signals> documentation that discourages its use for related elements, but when broadcasting a shared resource it seems just the thing. For example:
// source element
var db = SomeDB.init();
this.fire('iron-signal', { name: 'database', data: db });
<-- sink element -->
<iron-signals on-iron-signal-database="dbChange"></iron-signals>
class SinkElement {
dbChange(e, detail) {
this.db = detail;
this.db.getSomeData();
}
}