How can I tweak Knockout's writeable computed observeables to work with MVC model binding? - asp.net-mvc

I have a value for user display and a similar value for storage. How can I modify what I have so that I save the correct data to the model?
Fiddle
HTML
<div>formatted value for user display</div>
<input type="text" data-bind="value: formattedUnitOfCost" id="Model_Bound_ID" />
<div>unformatted value (the one I'd like to save)...this is not model bound</div>
<input type="text" data-bind="value: unitOfCost" />
JavaScript/Knockout
function AppViewModel() {
var self = this;
self.unitOfCost = ko.observable(1.01).extend({
isServerSet: false
});
self.formattedUnitOfCost = ko.computed({
read: function () {
return '$' + self.unitOfCost().toFixed(2);
},
write: function (value) {
// Strip out unwanted characters, parse as float, then write the raw data back to the underlying "price" observable
value = parseFloat(value.replace(/[^\.\d]/g, ""));
self.unitOfCost(isNaN(value) ? 0 : value); // Write to underlying storage
},
owner: self
});
}
ko.applyBindings(new AppViewModel());
The unformatted value is not displayed to the user. Model_Bound_ID is user editable.

You're doing it the wrong way.
Your model bound control (I mean the control that will be posted to your controller, and has the unformatted value) should be created like any other control, for example using Html.HiddenFor or whatever you want in your (Razor?) template. And you must add the data-bind attribute in the template. Remember that low-dash will be converted in medium-dash, so you can add it in the attributes parameter of the Html Helper like this: { data_bind = "value: unitOfcost" }.
Obviously this hidden field will be sent to the controller when posted (direct post, ajax, or whatever).
Now you need to add the visible control, and bind it to another observable. This observable will be a computed observable, which will do this:
on read, it will take the value from unitOfWork, and return it formatted
on write, it will parse the value to convert it to number, and update the unitOfWork observable with the parsed value
In fact you've got nearly all the code, but were implementing it all the way back.

Another way of looking at this answer is to change the html from this:
<input type="text" data-bind="value: formattedUnitOfCost" id="Model_Bound_ID" />
<input type="text" data-bind="value: unitOfCost" />
to this
<input type="text" data-bind="value: formattedUnitOfCost"/>
<input type="text" data-bind="value: unitOfCost" id="Model_Bound_ID" />
And KO does the rest by the power of the observables. Gosh I love KO

Related

Styling single jQuery UI controlgroup-item

I am using jQuery UI controlgroup to style checkboxes in an HTML form. After the input values are processed by a PHP script, the results are displayed on the the same page along with the form itself, so that the user can adjust the filters. What I am trying to do, is to have the boxes that were checked previously remain checked after the form has been processed, so that the user sees what selection criteria were used. To achieve that I store all the PHP $_POST data in a JS variable using json_encode, which I'd like to use to iterate through the labels and mark those that were checked previously. The problem is that the only option of the controlgroup widget that I can use is classes with ui-controlgroup-item which shows every single label within the group as active, and for the life of me I cannot figure out how to make it conditional, e.g. so that I can use if(label[for=' + var.value +'])', var being <?php echo json_encode($_POST) ?> or something similar. Will appreciate any suggestions.
Here is the HTML:
<div id="currencyList">
<label for="gbp">GBP</label>
<input type="checkbox" value="gbp" name="currency[]" id="gbp" >
<label for="usd">USD</label>
<input type="checkbox" value="usd" name="currency[]" id="usd">
<label for="eur">EUR</label>
<input type="checkbox" value="eur" name="currency[]" id="eur">
</div>
And this is the JavaScript bit:
$( "#currencyList" ).controlgroup({
classes: {
"ui-controlgroup-item": "ui-checkboxradio-checked ui-state-active"
}
});
After trying to find a solution for several days I decided to skip trying via the classes option and instead to move outside the controlgroup widget. So here is my not-so-pretty-but-working solution:
var postData = <?php echo json_encode($_POST) ?>;
$( "#currencyList" ).controlgroup();
$('#currencyList').children('label').each(function () {
if(postData.currency.indexOf($(this).attr("for")) >= 0){
$(this).addClass( "ui-checkboxradio-checked ui-state-active");
}
});

Retrieve value of slider

I am trying after reading manual get slider working. It returns Null. What I am doing wrong? How do I get current value form slider?
$('#slider-fill').slider();
var value = $('#slider-fill').slider("option", "value");
$(document).on('vclick', '#test', function(){
alert(value);
});
<input name="slider" id="slider-fill" value="1" min="1" max="10" step="1" data-highlight="true" type="range">
sdfsdf
Fiddle: http://jsfiddle.net/smatisen/eupjvf2x/
You want to use jQuery .val() -- which gets the value of an input.
alert($('#slider-fill').val());
http://jsfiddle.net/TheFiddler/eupjvf2x/2/
You shouldn't need the value var at all, I don't think.

All radioButtons are false at the view

#Html.RadioButton("smth",true)
This row at the page looks like UNCHECKED radioButton. Why?
You should use
HtmlHelper.RadioButton(string name, object value, bool isChecked)
extension method.
First argument is the name of the form field which is input field generated by html helper.
Second argument is the value of input element. If this radio is selected when the postback to server happens, this value is used.
Third argument is what you are looking for. If it is true it makes radio button selected.
For instance,
#Html.RadioButton("Name", "Value" ,true)
would generate an input element which looks like following,
<input checked="checked" id="Name" name="Name" type="radio" value="Value" />
You need to use something of the form
#Html.RadioButton(id,value,checked (bool true/false))
So
#Html.RadioButton("A","B",true)
For example would produce:
<input checked="checked" id="A" name="A" type="radio" value="B" />
The documentation for this is here
In your previous query, you got this answer.
You asked the same query in it's comment section. The problem was that the second line of code was missing one parameter.
Please check below details....
Parameter Details
Razor Syntax
#Html.RadioButton("smth", "smth", true)
#Html.RadioButtonFor( m => m.Prop, true, new { id = "rdBtn" } )

knockoutjs jquery mobile checkbox list issue: cannot check

With knockoutjs and jquery mobile, I need to create a list of checkboxes from an array. It seems the checkbox list is rendered, but it did not respond to click. http://jsfiddle.net/9zx7F/
I used a fieldset tag with data-role of controlgroup to build the list. I tried ul with listview as well, same issue.
Edit: further details - I found it seems related to timing of ko.applyBindings happens. I created a page with same code running on my localhost, it was okay. Then added a timer around ko.applyBindings, the issue happened again. http://jsfiddle.net/gonglei/9zx7F/12/
I solved this with two steps;
1) unwrapping the label from the input and hooking them together with 'for' attribute
<input type="checkbox" data-role="checkbox" data-bind="uniqueName: true, uniqueID: true, value: ID />
<label data-bind="uniqueIDFor: true" >Click me</label>
ko.bindingHandlers.uniqueIDFor = {
init: function (element) {
element.setAttribute("for", "ko_unique_" + ko.bindingHandlers.uniqueName.currentIndex);
}
};
ko.bindingHandlers.uniqueID = {
init: function (element) {
element.setAttribute("id", "ko_unique_" + ko.bindingHandlers.uniqueName.currentIndex);
}
};
2) telling jqm to update the new content
$('input:checkbox').trigger('create');
I would change the model for this:
<!-- ko foreach: listItems-->
<input type="checkbox" name="itemsList" value="name" />
<span data-bind="text: name"></span>
<!-- /ko -->
the main thing to consider is the "value" property in the input control to render in the proper way.
Regards.
#tredder's solution works! Here's a fork of your fiddle using the attr data-bind attribute to bind the label, which to me looks cleaner: http://jsfiddle.net/aib42/AnKR6/

MVC-entering text into textbox with on click event

I have view for entering new entity. On that view I have two buttons: one for saving new entity and another button should enter value into textbox on that form but I can't achieve this, the value in the textbox stays same as it was on page load. Does anyone know how to do this?
Thx
There are two possibilities:
Use javascript
Reload the page with additional query string containing the new value
Example with jquery:
<input type="text" name="foo" id="foo" value="old value" />
<input type="button" id="update" value="Update value" />
and the script
$(function() {
$('#update').click(function() {
$('#foo').val('some new value');
});
});

Resources