I am quiet recent to angular 2 and was bumping my head around two way data binding. Here is the confusion:
<input (input)="username = $event.target.value" id="testing">
<p>{{username}}</p>
This serves the purpose well. It already seems to be two way data binded. I can access username inside the component and the value property of the input element is updated as well. Why do i need [ ] at all then? What is the two way binding here? what goes inside the component and what comes out of the component.
Disclaimer: I know it's a very naive and seemingly stupid question :|
As i understand write like you did:
(input)="username = $event.target.value"
is the same as:
[(input)]="username"
So they're both 2 way data binding
if you want only one way:
(input)="username"
https://angular.io/docs/ts/latest/guide/template-syntax.html
Angular 2 data binding is explained here.
When you write in the input you execute: "username = $event.target.value", wich assigns to the variable user the value you enter.
That means that the following html does the same:
[(ngModel)]="username"
[username]="username" (input)="updateUserName()"
(input)="username = $event.target.value" and {{userName}}
Related
so in my angular 5 app i have the following code :
<div *ngFor='let part of (post.student | async).get("qcm")'>
<mat-checkbox>this can't be checked in or checked out</mat-checkbox>
</div>
post.student is of type PromiseObservable.
post.student | async is of type DocumentSnapshot (a Firestore document).
(post.student | async).get("qcm") is an array of three objects.
my problem is :
1) the checkbox is not working (can't be checked in or out)
2) if i try to apply the ngModel directive on the checkbox like so:
<div *ngFor='let part of (post.student | async).get("qcm")'>
<mat-checkbox [(ngModel)]='myBool'>this can't be checked in or checked out</mat-checkbox>
</div>
then the whole site blocks, using task manager i can see that my site have memory leaks now :
task manager
please note that if i use another array of objects other than (post.student | async).get("qcm") everything works fine.
also there are no errors in the console.
i have no idea what's going on, any help is appreciated, thank you!
Since I can't add comments, I just try to post some info that might help you here as an answer.
I don't think you can just add ngModel like that. You have to bind it to an object, like [(ngModel)]="myDataModel". Note that the [] and () are there so there is a two way binding, meaning whatever is in you myDataModel object, will be reflected at the checkbox any time. (So basically - so if you change the model, the cehckbox will change and if you cahnge the checkox the model will change). You dont have to always add two way binding, check the angular site for more information about this.
Also, the checkbox thingy might be a js thingy, check your browser console for errors. I assume some error happened and it interrupted the running of the js code.
I hope it somewhat helps finding your problem.
I am writing a page using Vue.js and am attempting some custom components. I've started with a very simple one:
Vue.component('single-field', {
template: '<b>{{ key }}:</b> {{ value }}',
props: ['key', 'value']
});
This works fine on its own: it is intended to take two values and return them in a key: value format. Initially, when I was passing the value as an element from the Vue data object (specifically, pickup.dateTime it wasn't working. It's easier to show than explain:
<div id="app">
<single-field key="Date & Time" value="pickup.dateTime"></single-field>
</div>
I was able to fix this by binding the value (notice the colon by value):
<single-field key="Date & Time" :value="pickup.dateTime"></single-field>
I then wrote a second component which is designed to take an object and a title and return each element of the object as a set of <single-field> components, with a title above them. Here is what I wrote:
Vue.component('field-block', {
template: '<h2>{{title}}</h2>\
<div v-for="(p-key, p-value) in parent">\
<single-field key="p-key" value="p-value"></single-field>\
</div>',
props: ['parent', 'title']
});
Now, I think there must be something wrong with the way I am binding (or not binding?) which is causing the data to be displayed in a strange way. Here is my HTML:
<div id="app">
<single-field key="DateTime" :value="pickup.dateTime"></single-field>
<single-field key="Name" :value="pickup.name"></single-field>
<field-block title="Address" :parent="pickup.address"></field-block>
</div>
The field pickup.address is an object, so I was hoping that the component would iterate through the elements and return them as single fields, but what it's currently doing is just returning the variable names, like p-key: p-value. I tried doing a bind on both of them in the component definition (on both because they are now both variables being passed whereas previously I was using a static string for the key field):
<div v-for="(p-key, p-value) in parent">
<single-field :key="p-key" :value="p-value"></single-field>
</div>
But what this returns is NaN: NaN, and I can't figure out why it would do that. I don't fully understand the bind operation, but I expect that it only binds to data in the data option when defining the view, which is not where p-key and p-value are defined. How would I get the variables to 'carry through' from the outer component to the inner ones? Thanks.
Okay this one was tricky.
Several problems with your code:
Your components should have only one root element. So pack your components into a <div>.
Then, - is not a valid character to put into a javascript variable name. So you can't write (p-key, p-value) in parent, write something else, like (pKey, pValue) in parent.
On the other hand, html properties are not case-sensitive, so you should actually write key-name (for example) instead of keyName, but only for the property names. This limitation does apply only in your html files (not in your string templates).
Finally, here is a working js-fiddle.
https://jsfiddle.net/6juwLd3b/
Additionally, I would advise you that you look at your console while developing. Many error where displayed that could have lead you to a working version.
I'm actually not sure how to ask this question, and I'm probably using incorrect terms, so bear with me.
Angular sets up a 2-way data binding so that it makes it easy to work with the data on both sides. But what if I want to change how that data is represented?
Let me give a concrete example.
I want a form with a checkbox, which if bound directly to a model, would be stored as true or false by Angular. However, in another part of the webpage I want that value to show up as 0 or 1, not true or false.
Now sure I could go and make them use two different variables, and use ng-change or something like that to update one based on the other, but that seems overkill and convoluted.
Is there some special meta function or something I can define that lets me essentially translate the data as it goes back and forth?
Use the ngTrueValue and ngFalseValue directives. They define what should be treated as true and false on a checkbox: https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D
Example:
<input type="checkbox" ng-model="foo"
ng-true-value="OK"
ng-false-value="BOO-HOO">
The model will either have a value of "OK" or "BOO-HOO" instead of the default true and false in the above example.
Alternatively, if you want the original model to retain its default values and only draw the custom ones from another variable, you could also use the ngChange directive:
<input type="checkbox" ng-model="foo"
ng-change="bar=foo&&'OK'||'BOO-HOO'">
Now, whenever foo changes, bar will have the corresponding alternative value. Just remember to assign bar an initial value (it will start out with no value at all).
in your controller...
$scope.getvalue(data)
{
if(data===true)
return 1; // write what ever you want...
return 0;
}
in your html page..
bind the normal one as {{$scope.data1}} and other as {{getvalue($scope.data1)}}
You can do some nice things with ngBind:
Check this plunker: http://plnkr.co/edit/cRhLN2p5N4PmI65ps6Gp?p=preview
<input type="checkbox" ng-model="ok"> OK?
<h2>true or false: {{ ok }}</h2>
<h2>0 or 1: {{ ok ? 1 : 0 }}</h2>
I have a Person class where edits made to the person must be verified by an admin user.
Each attribute has an "approved" and "tmp" version. Sometimes the "tmp" version is not set:
person = {first:'Bob', firstTmp:'Robert', last:'Dobbs', lastTmp:undefined}
When displaying the person, I want to display the "tmp" value if it is set, otherwise display the "approved" value. When writing, I want to write to the "tmp" value (unless logged in as an admin).
Ideally, this would not require a lot of custom markup, nor writing cover methods for each property (there are around 100 of them). Something like this would be nice:
<input ng-model="person.first"
tmp-model="person.firstTmp"
bypass-tmp="session.user.isAdmin" />
When displaying the value, display the tmp value if it is defined. Otherwise display the approved value.
When writing the value, write to the tmp value, unless logged in as an admin. Admins write directly to the approved value.
What's a good clean way to implement this in Angular?
Extend NgModelController somehow?
Use a filter/directive on the input?
Cover methods?
Just do the writing server-side?
I will try to go through your options one by one:
Extend NgModelController somehow?
I don't think this is a good idea. It won't be nice if something goes wrong and you don't know if you can even rely on something as basic as ng-model
Just do the writing server-side?
This would seem like the easier way (if you already know or find it easy to manage it in the back end), although the interaction would need a new request to the server.
Use a filter/directive on the input?
I believe this would be the best way to do it, as it is easy to understand what is going on by just taking a look at the markup. It's angular, you already know that some property like tmp-model is extending the markup.
Cover methods?
This would also be easy to implement, and you would be implementing some sort of "business logic" as a validator in your cover method.
Given that I've extended a bit in my answer, I can give you an inline example of the last one.
<input ng-model="person.firstTmp"
ng-init="person.firstTmp = person.firstTmp || person.first"
ng-change="updateProperty(person, 'first')" />
And on the controller, you could do something like:
$scope.updateProperty = function(person, propertyName) {
// The temporary property has already been changed, update the original one.
if($scope.session.user.isAdmin)
person[propertyName] = person[propertyName + 'Tmp'];
}
Following up on this queston/answer (second answer) Dynamically loading templates in Meteor.js
I have set up a helper in the current displayed template and i am returning the template dynamically. This works great.
Template.template1.helpers({
dynamicView: function(){
return Template['dynamic_template']();
}
})
This ends up showing my html in template 1:
Questions:
How do i pass data to this Template as it's being created, can i do something like this:
Template['dynamic_template'](data1, jsonData2);
I want the dynamicView helper in template1 to also be dynamic in the sense that it can have a different template based on some other criteria. Can i use a Session here and change the dynamicView return statement to something like this:
dynamicView: function(){
return Session.get('dynamicTemplate');
}
and somewhere else Session.set('dynamicTemplate', Template['dynamic_template']()); This works, but is it recommended. It's just a string but i am concerned about performance problems and the size of my template being passed reactively
OK I guess ill have to split my answer up:
With 1.
The templates are compiled handlebars templates so you just need to provide a context to them so the handlebars data can be filled up:
data = {name1:value1, name2:value2}
return Template['dynamic_template'](data);
So that {{name1}} and {{name2}} get filled up with value1 and value2 respectively.
With 2.
Yes that should work, you can pass off any data that will give off HTML as a result. For a very detailed videocast have a look at the EventedMind screencast on template functions: http://www.eventedmind.com/posts/meteor-rendering-template-functions
The template system's use case might not be this exactly. You might want to use Meteor.render instead, but it depends on what you want to do.
Despite the Session name, its just a reactive javascript variable so it should be fine with larger strings too to the same that would be used in an ordinary javascript variable