Knockout databinding of input type? - data-binding

Can you databind the type of an input control? Like something like this:
I believe I can just use the and surround some controls so that I could have a different input control for each type when necessary. But I thought I'd check if there was a way to bind the type and change it on the fly that way.

The attr binding lets you bind attribute values like:
<input data-bind="attr: { type: something }" />
http://knockoutjs.com/documentation/attr-binding.html
http://jsfiddle.net/rniemeyer/h6n6oa6v/

Related

Nativescript Repeater databinding

I want to create a dynamic menu list, and apply class at selected item.
I have an array of menu entries, menuItems which is an observableArray.
The page binding contain two entries :
menuItems
selectedPage
The idea is simple : apply a different class when the selectedPage parameter equal the page name to indicate to user which page is currently displayed.
<Repeater items="{{menuItems}}" id="repeater">
<Repeater.itemTemplate>
<Label text="{{name}}" class="{{ $parents['Page'].selectedPage == name ? 'selected' : '' }}" tap="navigate" />
</Repeater.itemTemplate>
</Repeater>
This doesn't work, so I have made some tests, and a strange thing happened.
When I use a simple Label into my Repeater to test my bindings, I can acces the good datas.
<Label text="{{name}}"/>
Display the good menuItems entry name.
<Label text="{{$parents['Page'].selectedPage}}"/>
Display the good selectedPage entry name.
But, these code samples doesn't work together. Both works only independently.
So, I'm a bit lost, is using a $parents based selector change the context inside the Repeater ?
I too have encountered this issue and found the solution in NativeScript's documentation on data binding:
Note: Binding expression could be used without explicitly named source property ( TextField text="" ). In that case $value is used as a source property. However this could lead to problems when a nested property should be observed for changes (e.g. item.nestedProp). $value represents bindingContext and when any property of the bindingContext is changed expression will be evaluated. Since nestedProp is not a property of the bindingContext in item.nestedProp then there will be no propertyChange listener attached and changes to nestedProp will not be populated to UI. So it is a good practice to specify which property should be used as source property in order to eliminate such issues.
What this means is that when you're binding a variable that's set directly on your binding context, you can pass the expression into the curly brackets by itself:
<Label text="{{name}}" class="{{ mySelectedPage == name ? 'selected' : '' }}" tap="navigate" />
...but if you're binding a variable that's nested within an object which is set on the binding context, you must pass that nested property into the curly brackets as the first parameter, and the expression itself as the second parameter:
<Label text="{{name}}" class="{{ $parents['Page'].selectedPage, $parents['Page'].selectedPage == name ? 'selected' : '' }}" tap="navigate" />

How to bind to complex objects with radios and checkboxes in AngularJS?

Say we have a set of projects exposed via the Project service:
{ id: '123', name: 'Yeoman', watchers: '1233', ... }
{ id: '123', name: 'Grunt', watchers: '4343', ... }
Then, we have a form to choose your favorite project:
Select favorite project:
%label.radio(ng-repeat="project in Project.query()")
%input(type="radio" ng-model="data.favoriteProject" value="{{project.id}}") {{project.name}}
This sets choices.favoriteProject to the id value of the chosen project. Often, we need to access the related object, not just the id:
John's favorite project:
{{Project.get(data.favoriteProject).name}}
What I'm looking for is a way to bind the radios and checkboxes straight to the object itself, not the id, so we could do
John's favorite project:
{{data.favoriteProject.name}}
instead. This is possible with select directive via ng-options, but how can we do this with radios and checkboxes? I'd still like to use the ids for matching instead of references, if possible.
To clarify, here's an example what I'm looking for
Select favorite project:
%label.radio(ng-repeat="project in Project.query()")
%input(type="radio" ng-model="data.favoriteProject" value="{{project}}" ng-match="id") {{project.name}}
It says: "Please bind data.favoriteProject to the actual project object and use the id to check if they match (instead of references)".
[Update]
I've completely changed my answer after discovering the ngValue directive, which appears to be undocumented. It allows you to bind objects instead of just strings as values for ngModel on the radio button inputs.
<label ng-repeat="project in projects">
<input type="radio" ng-model="data.favoriteProject"
ng-value="project">{{project.name}}</input>
</label>
<p>Your favorite project is {{data.favoriteProject.name}}.</p>
This uses references to check rather than just IDs, but I think in most cases, this is what people will be looking for. If you do very strictly only want to match based on IDs, you can use the [Old Answer], below, or even better, just create a function--e.g. projectById(projectId) that you can use for looking up a project based on its ID.
I've updated the JSFiddle to demonstrate: http://jsfiddle.net/BinaryMuse/pj2GR/
[Old Answer]
Perhaps you can utilize the ng-change attribute of the radio button directive to achieve what you want. Consider this HTML:
<p>Select your favorite project:</p>
<label ng-repeat="project in projects">
<input type="radio" ng-model="data.favoriteProjectId" value="{{project.id}}"
ng-change="data.favoriteProject = project">
{{project.name}}
</input>
</label>
<p>Your favorite project is {{data.favoriteProject.name}}.</p>
You could also call a function inside ng-change, for example setfavoriteProject(project)--but I did not do that here for simplicity's sake.
Here is a working jsFiddle to demonstrate the technique: http://jsfiddle.net/BinaryMuse/pj2GR/7/
No ng-change needed (and I'm not sure, if it is a good practise to write inline-code like this. On the other hand angulars directives are not too far from it theirselves). Why not just do something like this (works with ng-repeat as well):
Fiddle:
http://jsfiddle.net/JohannesJo/VeZxh/3/
Code:
<body ng-app="app">
<div ng-controller='controller'>
<input type = "radio" ng-model = "oSelected" value = "{{aData[0]}}">
<input type = "radio" ng-model = "oSelected" value = "{{aData[1]}}">
<div>test: {{oSelected}}</div>
</div>
</body>
app = angular.module('app',[]);
app.controller('controller', function($scope){
$scope.aData = [
{o:1},
{o:2}
];
$scope.oSelected = {};
});
Edit: I maybe should mention that this doesn't work for checkboxes, as value will either be true or false. Also a shared model will lead to all checkboxes either being checked or unchecked at the same time.

ASP.NET MVC3: Razor GetHTML Table custom layout

Im manually Creating the table using the built in razor GETHtml Function.
#table.GetHtml(
columns: table.Columns(
table.Column("Account"),
table.Column("Due"),
table.Column("Topic"),
table.Column("Type"),
table.Column("Completed?", format: #<input id="Complete" name="Complete" type="checkbox" onclick="/Tasks/Complete?ID=700" />)
)
)
What I want is a way of clicking a checkbox, or button to activate the controller. it is not accepting Dynamic checkbox. Nor does the html checkbox do anything.
I Have a working solution without using forms, the column would be set using the following code:
table.Column("Completed?", format: #<input type="checkbox" onclick="location.href='#Url.Action("Complete", "Tasks", new { TaskID = item.TaskID })'" />
I think its possible that having the name property was causing it to post it as a parameter, rather than treat it as a submit.
Otherwise it must ahve been the onclick event. Ive used location.href, then set it using razor syntax, and included the id as a property.
Couple of ways to go about performing a post to your desired controller. Wrap your table with the form you would like to submit or add a few AJAX handlers to post the data you desire. A simple form could be accomplished like:
<% using (Html.BeginForm<SomeController>(x=> x.SomeAction())
{
#table.GetHtml(
columns: table.Columns(
table.Column("Account"),
table.Column("Due"),
table.Column("Topic"),
table.Column("Type"),
table.Column("Completed?", format: #<input id="Complete" name="Complete" type="submit" " />)
)
)
}

ASP.net can't set checkboxes value!

CheckBox newBox = new CheckBox();
newBox.Text = dtCommon[i].userName;
newBox.CssClass = "cbox";
newBox.Attributes["value"] = dtCommon[i].id.ToString();
ApprovalSelectPanel.Controls.Add(newBox);
Renders as:
<input id="ctl00_mainContent_ctl00" type="checkbox" name="ctl00$mainContent$ctl00" checked="checked" />
How can I get a value attribute on? My JQuery needs to access this!
I bet you it is setting the attribute, but on the containing span (look up one element).
You want to use the InputAttributes property instead:
newBox.InputAttributes["value"] = dtCommon[i].id.ToString();
newBox.Attributes.Add("yourAttributeName", "yourAttributeValue");
EDIT: Sorry I forgot checkboxes act a little diff so you need to do:
newBox.InputAttributes.Add("yourAttributeName", "yourAttributeValue");
If you want to access the span around the checkbox control the original would work or you could do:
newBox.LabelAttributes.Add("yourAttributeName", "yourAttributeValue");
Can you try newBox.Attributes.Add("Value", dtCommon[i].id.ToString());
If you need to store a value on the checkbox, I recommend using something besides value, such as "MyValue". You can still get this "MyValue" using the .Attributes method later in your processing. In jquery, you could use the .attr('MyValue') to obtain the value.

Range validation

Suppose I have a table like:
create table
{
id numeric(5,3),
code varchar(10)
}
I have two text boxes in my form for the two fields.
Suppose if I type 1234578 in the first text box the error has been thrown in ASP.NET because I crossed the limit.
How can I validate in JavaScript or some other way for that particular range validation?
Let's take one textbox only. Attach an 'onchange' event handler to your textbox like this:
<input type="text" onchange="handleChange(this);" />
Then declare a script for validation like this:
<script>
function handleChange(input) {
if (input.value > ..your_value_here..) alert ("Invalid input");
}
</script>
Please note that the alert pop-up used here should not be actually used. Use a more subtle reminder at a more appropriate moment. The alert here is only to make things simple.

Resources