Meteor binding values for inputs with event generation - javascript

I have a form input with a value bound to a reactive data source:
<input type="text" name="first-name" id="first-name" required value="{{currentUser.profile.firstName}}" />
I want to watch 'change' events on the input:
$('#first-name').change(function() { alert('Value changed!'); });
This works fine if I change the value directly in the input. However, if the value changes reactively, the change event doesn't fire.
What's the best way to bind values to form elements so that the 'change' event fires if the reactive data source changes?

The Optimum Solution would be to use manuel:viewmodel. You keep the state of the UI in a javascript object and bind the UI elements to properties of that object.
Example :
First add the package to the project with meteor add manuel:viewmodel
Then in the Html do the Following :
<template name="loginBox">
First Name: <input type="text" data-bind="value: first"/>
<br/>
Last Name: <input type="text" data-bind="value: last"/>
<div data-bind="text: greeting"></div>
<a data-bind="enabled: canEnter, hover: showError" class="btn-primary">Enter Site</a>
<span data-bind="text: errorText" class="text-error"></span>
</template>
Then in the Javascript file do the Necessary Bindings
Template.loginBox.viewmodel({
first: '',
last: '',
greeting: function() {
return "Hello " + this.first() + " " + this.last();
},
canEnter: function() {
return !!this.first() && !!this.last();
},
showError: false,
errorText: function() {
if (this.canEnter() || !this.showError()) {
return '';
}
return "Please enter your first and last name";
}
});
Here we're binding the value of the input/text element to the property 'first' of the viewmodel.
The result is that the viewmodel object will be kept in sync with the input box. If you change the value in the texbox then the value of the viewmodel's 'first' property will also change and vice versa.
For More information http://viewmodel.meteor.com/

Here's my initial solution, which I'm not particularly thrilled with:
Template.signUpPersonalDetails.rendered = function() {
this.autorun(function() {
if (Meteor.user() && Meteor.user().userAccount) {
var userAccount = Meteor.user().userAccount;
$('#first-name').val(userAccount.firstName).change();
$('#last-name').val(userAccount.lastName).change();
$('#email').val(userAccount.email).change();
$('#phone-number').val(userAccount.phoneNumber).change();
$('#postcode').val(userAccount.shippingPostcode).change();
}
});
};

Related

2 way data binding in JavaScript

Two-way data binding refers to the ability to bind changes to an object’s properties to changes in the UI, and vice-versa.
Can we achieve 2-way data-binding with JavaScript?
Especially 2 Way Data Binding without Frameworks.
When an input is changed update the value, add a setter to the value which sets the inputs content. E.g this element:
<input id="age">
And some js:
var person = (function(el){
return {
set age(v){
el.value = v;
},
get age(){
return el.value;
}
};
})(document.getElementById("age"));
So you can do:
person.age = 15;
And the input will change. Changing the input changes person.age
Yes, we can achieve the two way data binding using pure javascript.
twoWay=function(event) {
var elem = document.getElementsByClassName(event.currentTarget.className);
for(var key in elem){
elem[key].value=event.currentTarget.value;
}
}
You can check the jsfiddle.
Simple and working approach to two-way binding, only using vanilla JS.
<!-- index.html -->
<form action="#" onsubmit="vm.onSubmit(event, this)">
<input onchange="vm.username=this.value" type="text" id="Username">
<input type="submit" id="Submit">
</form>
<script src="vm.js"></script>
// vm.js - vanialla JS
let vm = {
_username: "",
get username() {
return this._username;
},
set username(value) {
this._username = value;
},
onSubmit: function (event, element) {
console.log(this.username);
}
}
JS Getters and Setters are quite nice for this - especially when you look at the browser support.
Yes indeed.
There are frameworks like angular Js which provides full support for two way data binding.
And if you want to achieve the same in vanilla js you can bind value into view
Eg. document.getElementById('test').value="This is a Test"
And to bind view value to the controller you can trigger onchange event in html.
<Input type="text" id="test" onchange="Func()">
LemonadeJS is another micro-library (4K), with no dependencies worth looking at.
https://lemonadejs.net
https://github.com/lemonadejs/lemonadejs
Adding a little elaboration to Jonas Wilms answer, here's a sample without currying and also adds event binding for a full two way bind.
// Property binding
var person = {
set name(v) {
document.getElementById('name').value = v;
},
get name() {
return document.getElementById('name').value;
},
set age(v) {
document.getElementById('age').value = v;
},
get age() {
return document.getElementById('age').value;
}
};
// You can now set values as such
person.name = 'Cesar';
person.age = 12;
// Event binding completes the two way
function logToConsole(event) {
console.log(event.target.value);
}
// You can set person.name or person.age in console as well.
<label for="name">Name: </label><input id="name" onkeyup="logToConsole(event)">
<label for="age">Age: </label><input id="age" onkeyup="logToConsole(event)">
Would you mind if it would be a small component for databinding tasks that provides enough convenient databinding definition commands. I did it with databindjs. e.g.
// Lets assume that there is just simple form (target)
var simpleForm = {
input: $('.simple .input-value'),
output: $('.simple .output-value')
};
// And here is the simple model object (source)
var model = {
text: 'initial value'
};
// Lets set two directional binding between [input] <-> [text]
var simpleBinding = bindTo(simpleForm, () => model, {
'input.val': 'text', // bind to user input
'output.text': 'text' // simple region that will react on user input
});
// This command will sync values from source to target (from model to view)
updateLayout(simpleBinding);
subscribeToChange(simpleBinding, () => {
$('.simple .console').html(JSON.stringify(model));
});
// Just initialize console from default model state
$('.simple .console').html(JSON.stringify(model));
The full solution here.
You can check the full implementation of the databinding core on github

Dynamic button enable knockout js based on error group

I have a text box and a button. When the text box is empty, I need the button to be disabled and when I start typing in the text box, I want the button to be enabled.
Currently, after inputing some text in the text box, the button is enabled the moment I focus out of the text box. But I want this to be enabled the moment is text box is not empty. I am using knockout.js and both my text box and the button are observables.
I have nore than 1 text field and I want to enable if all fields are not empty. If any field is empty, without loosing focus, I want to disable the button
Here's my code:
var email = ko.observable({ emailField: ko.observable().extend({ email:
true, required: { param: true, message: FILL_FIELD } })), enableButton
= ko.observable(), errorGroup = ko.validation.group([emailField]);
<input type="text" data-bind="value:emailField" />
<button data-bind="enable: enableButton>Press Next to enter password</button>
You have two options:
Use textInput for KO 3.2.0 and higher; or
Use value alongside valueUpdate: 'afterkeydown' for lower versions;
Both make sure your view model is updated immediately after key presses, cascading to other bindings like enable.
The thing that complicates your question is that you've got validation going on, and you want the validation to wait until focus exits, so having the values update continuously with your typing is not a solution.
Instead, you could watch input events separately, to keep track of which of your required fields are empty. watchForEmpty is a factory that takes an observable and returns a Knockout event handler. It sets up the initial state of the list of empties, and the event handler maintains it. The button is enabled when the list of empties has no entries.
vm = {
empties: ko.observableArray(),
thing: ko.observable('prefilled'),
thing2: ko.observable(),
watchForEmpty: function(observable) {
var initVal = observable();
if (initVal === '' || initVal === undefined) {
vm.empties.push(observable);
}
return function(context, event) {
var el = event.target;
if (el.value === '') {
vm.empties.push(observable);
} else {
vm.empties.remove(observable);
}
};
}
};
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input data-bind="value: thing, event: {input: watchForEmpty(thing)}" />
<input data-bind="value: thing2, event: {input: watchForEmpty(thing2)}" />
<button data-bind="enable: empties().length === 0">Go</button>
<div data-bind="text: thing"></div>
<div data-bind="text: thing2"></div>

Form validation - Required one of many in a group

In the project I'm working on at the moment I currently have three textboxes and I need to validate that at least one of the text boxes has been populated.
I've been reading into custom validation with Angular directives and I understand you can set the validity of an input in a directive's link function using the following:
ctrl.$parsers.unshift(function(viewValue) {
// validation logic here
});
The problem I have is that I don't need to set an individual input's validity.. I need to invalidate the entire form if the criteria isn't met. I just wonder how to approach this?
I'm thinking maybe I should create a directive that's placed on the enclosing form itself and then make the form invalid?
I suppose I'm just looking for some guidance into how I should go about this because I'm a little unclear where to start - all the material I'm reading on custom validation seems to be for when you're validating a specific input as opposed to a set of conditions on a form.
I hope I've made myself clear! Thanks..
You can use ng-required to force the user to fill at least one field by checkingthe length attribute of the string.
You can do the following for example:
<form name="myForm">
<input type="text" ng-model="fields.one" name="firstField" ng-required="!(fields.one.length || fields.two.length || fields.three.length)" />
<br/>
<input type="text" name="secondField" ng-required="!(fields.one.length || fields.two.length || fields.three.length)" ng-model="fields.two" />
<br/>
<input type="text" ng-model="fields.three" name="thirdField" ng-required="!(fields.one.length || fields.two.length || fields.three.length)" />
<br/>
<button type="submit" ng-disabled="!myForm.$valid">Submit</button>
</form>
See this working fiddle example for more details.
You can have more details about required vs ng-required by reading this question
There are several approaches and the best option depends on your exact requirements.
Here is one approach that I found to be generic enough and flexible.
By "generic" I mean it doesn't only work for text-fields, but also for other kinds of inputs, such as check-boxes.
It's "flexible" because it allows any number of control-groups, such that at least one control of each group must be non-empty. Additionally, there is no "spacial" constraint - the controls of each group can be anywhere inside the DOM (if required, it is easy to constrain them inside a single form).
The approach is based on defining a custom directive (requiredAny), similar to ngRequired, but taking into account the other controls in the same group. Once defined, the directive can be used like this:
<form name="myForm" ...>
<input name="inp1" ng-model="..." required-any="group1" />
<input name="inp2" ng-model="..." required-any="group1" />
<input name="inp3" ng-model="..." required-any="group1" />
<input name="inp4" ng-model="..." required-any="group2" />
<input name="inp5" ng-model="..." required-any="group2" />
</form>
In the above example, at least one of [inp1, inp2, inp3] must be non-empty, because they belong to group1.
The same holds for [inp4, inp5], which belong to group2.
The directive looks like this:
app.directive('requiredAny', function () {
// Map for holding the state of each group.
var groups = {};
// Helper function: Determines if at least one control
// in the group is non-empty.
function determineIfRequired(groupName) {
var group = groups[groupName];
if (!group) return false;
var keys = Object.keys(group);
return keys.every(function (key) {
return (key === 'isRequired') || !group[key];
});
}
return {
restrict: 'A',
require: '?ngModel',
scope: {}, // An isolate scope is used for easier/cleaner
// $watching and cleanup (on destruction).
link: function postLink(scope, elem, attrs, modelCtrl) {
// If there is no `ngModel` or no groupName has been specified,
// then there is nothing we can do.
if (!modelCtrl || !attrs.requiredAny) return;
// Get a hold on the group's state object.
// (If it doesn't exist, initialize it first.)
var groupName = attrs.requiredAny;
if (groups[groupName] === undefined) {
groups[groupName] = {isRequired: true};
}
var group = scope.group = groups[groupName];
// Clean up when the element is removed.
scope.$on('$destroy', function () {
delete(group[scope.$id]);
if (Object.keys(group).length <= 1) {
delete(groups[groupName]);
}
});
// Update the validity state for the 'required' error-key
// based on the group's status.
function updateValidity() {
if (group.isRequired) {
modelCtrl.$setValidity('required', false);
} else {
modelCtrl.$setValidity('required', true);
}
}
// Update the group's state and this control's validity.
function validate(value) {
group[scope.$id] = !modelCtrl.$isEmpty(value);
group.isRequired = determineIfRequired(groupName);
updateValidity();
return group.isRequired ? undefined : value;
}
// Make sure re-validation takes place whenever:
// either the control's value changes
// or the group's `isRequired` property changes
modelCtrl.$formatters.push(validate);
modelCtrl.$parsers.unshift(validate);
scope.$watch('group.isRequired', updateValidity);
}
};
});
This might not be so short, but once included into a module, it is very easy to integrate into your forms.
See, also, this (not so) short demo.
It's too late but might be can save some one's time:
If there are only two fields, and want to make one of them required then
<input type="text"
ng-model="fields.one"
ng-required="!fields.two" />
<br/>
<input type="text"
ng-model="fields.two"
ng-required="!fields.one" />
If you have three like in question then
<input type="text"
ng-model="fields.one"
ng-required="!(fields.two || fields.three)" />
<br/>
<input type="text"
ng-model="fields.two"
ng-required="!(fields.one || fields.three)" />
<br/>
<input type="text"
ng-model="fields.three"
ng-required="!(fields.one|| fields.two)" />
If more than this, I will suggest to write a function on scope and watch it.
See the working example
modification to ExpertSystem's answer (https://stackoverflow.com/a/24230876/4968547) so that his code works in the latest angularjs.
i changed the updateValidity() to set parse also to true/false
function updateValidity() {
if (group.isRequired) {
modelCtrl.$setValidity('required', false);
modelCtrl.$setValidity('parse', false);
} else {
modelCtrl.$setValidity('required', true);
modelCtrl.$setValidity('parse', true);
}
}
now its working fine for me
Ran into this same problem last week; ExpertSystem's solution was a good start, but I was looking for a few enhancements to it:
Use Angular 1.4.3
Use ngMessages
I eventually wound up with this example on JSFiddle - hope that helps inspire others in the same boat! Relevant JS code from the Fiddle:
var app = angular.module('myApp', ['ngMessages']);
app.controller('myCtrl', function ($scope) {
$scope.sendMessage = function () {
$scope.myForm.$submitted = true;
if ($scope.myForm.$valid) {
alert('Message sent !');
}
};
});
app.directive('requiredAny', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function postLink(scope, elem, attrs, ctrl) {
// If there is no 'ngModel' or no groupName has been specified,
// then there is nothing we can do
if (!ctrl || !attrs.requiredAny) { return };
// If this is the first time we've used this directive in this scope,
// create a section for it's data. If you need / want to make use of
// an isolate scope you'll need to make 'var groups' scoped to the directive;
// but then you may want to look in to clearing out group entries yourself
if (!scope.__requiredAnyGroups) {
scope.__requiredAnyGroups = {}
}
var groups = scope.__requiredAnyGroups;
// Create a bucket for this group if one does not yet exist
if (!groups[attrs.requiredAny]) {
groups[attrs.requiredAny] = {};
}
var group = groups[attrs.requiredAny];
// Create the entry for this control
group[attrs.ngModel] = {
ctrl: ctrl,
hasValue: false
};
ctrl.$validators.requiredAny = function(view, value) {
var thisCtrl = group[attrs.ngModel],
ctrlValue = (typeof value !== 'undefined') && value,
oneHasValue = false;
thisCtrl.hasValue = ctrlValue;
// First determine if any field in the group has a value
for (var prop in group) {
if (group.hasOwnProperty(prop) && group[prop].hasValue) {
oneHasValue = true;
break;
}
}
// Set the validity of all other fields based on whether the group has a value
for (var prop in group) {
if (group.hasOwnProperty(prop) && thisCtrl != group[prop]) {
group[prop].ctrl.$setValidity('requiredAny', oneHasValue);
}
}
// Return the validity of this field
return oneHasValue;
};
}
};
});
Here is a refactored take on ExpertSystems great post. I didn't need the destroy method so I gutted it.
I also added a grayed out explanation that may help in your code. I use this directive for ALL my required fields. Meaning when I use this directive I no longer use ng-required, or required.
If you want a field required just pass in a unique group name. If you don't want the field required then pass in null, and if you want to have many different groups just pass in a matching group name.
I believe there is a little more refactoring that could be done here. Angularjs states that when using $setValidity, that instead you should use $validators pipeline instead, but I could not get that to work. I am still learning this complex animal. If you have more info, post it!
app.directive('rsPartiallyRequired', function () {
var allinputGroups = {};
return {
restrict: 'A',
require: '?ngModel',
scope: { },
link: function(scope, elem, attrs, ctrl) {
if( !ctrl || !attrs.rsPartiallyRequired ){ return } // no ngModel, or rsPartialRequired is null? then return.
// Initilaize the following on load
ctrl.$formatters.push( validateInputGroup ); // From model to view.
ctrl.$parsers.unshift( validateInputGroup ); // From view to model.
if ( ! allinputGroups.hasOwnProperty( attrs.rsPartiallyRequired )){ // Create key only once and do not overwrite it.
allinputGroups[ attrs.rsPartiallyRequired ] = { isRequired: true } // Set new group name value to { isRequired: true }.
}
scope.inputGroup = allinputGroups[ attrs.rsPartiallyRequired ] // Pass { isRequired: true } to form scope.
function validateInputGroup(value) {
scope.inputGroup[ scope.$id ] = !ctrl.$isEmpty( value ); // Add to inputGroup ex: { isRequired: true, 01E: false }.
scope.inputGroup.isRequired = setRequired( attrs.rsPartiallyRequired ); // Set to true or false.
updateValidity(); // Update all needed inputs based on new user input.
return scope.inputGroup.isRequired ? undefined : value
}
function setRequired(groupName) {
if( ! allinputGroups[ groupName ] ){ return false } // No group name then set required to false.
return Object.keys( allinputGroups[ groupName ] ).every( function( key ) { // Key is 'isRequired' or input identifier.
return ( key === 'isRequired' ) || ! allinputGroups[ groupName ][ key ]
});
}
scope.$watch('scope.inputGroup.isRequired', updateValidity); // Watch changes to inputGroup and update as needed.
function updateValidity() { // Update input state validity when called.
ctrl.$setValidity('required', scope.inputGroup.isRequired ? false : true );
}
}
}
});
// This directive sets input required fields for groups or individual inputs. If an object in the template is given
// to the directive like this:
// Object: { "name": "account_number", "attrs": { "required": { "group": "two" }}}.
// HTML: <input type="text" rs-partially-required="{{ field.attrs.required.group }}" />
// Or anything where the evaluation is a string, for example we could use "groupOne" like this...
// HTML: <input type="text" rs-partially-required="groupOne" />
// Then this directive will set that group to required, even if it's the only member of group.
// If you don't want the field to be required, simply give the directive a null value, like this...
// HTML: <input type="text" rs-partially-required="null" />
// However, when you want to use this directive say in an ngRepeat, then just give it a dynamic string for each input
// and link the inputs together by giving the exact matching string to each group that needs at least one field. ex:
// <input type="text" rs-partially-required="null" />
// <input type="text" rs-partially-required="one" />
// <input type="text" rs-partially-required="two" />
// <input type="text" rs-partially-required="one" />
// <input type="text" rs-partially-required="null" />
// <input type="text" rs-partially-required="three" />
// <input type="text" rs-partially-required="three" />
// <input type="text" rs-partially-required="three" />
// In the above example, the first and fifth input are not required and can be submitted blank.
// The input with group "two" is the only one in the group, so just that input will be required by itself.
// The 2 inputs with "one" will be grouped together and one or the other will require an input before
// the form is valid. The same will be applied with group "three".
// For this form to be valid, group "two" will be required, and 1 input from group one will be required,
// and 1 input from group three will be required before this form can be valid.
You can add required attribute for each of them , and at the end , you can rely your validation on each/all/or just one of them
<form name="form" novalidate ng-submit="submit()">
// novalidate is form disabling your browser's own validation mechanism
<input type="text" required ng-model="texts.text1">
<input type="text" required ng-model="texts.text2">
<input type="text" required ng-model="texts.text3">
// you can do validation in variety of ways , but one of them is to disable your submit button until one of the textboxes are filled correctly like this :
<button type="submit" ng-disabled="form.text1.$invalid && form.text2.$invalid && form.text3.$invalid"></button>
</form>
This way if just one of them is filled , button will be enable
I don't know how you're gonna show that form is not valid , but I think desabling the submit button is the general way
I had similar grouping requirement in my project and I wrote this.Interested people can use this
.directive('group',function(){
return {
require: '^form',
link : function($scope,element,attrs,formCtrl){
var ctrls =[];
element.find(".group-member").each(function(){
var member = angular.element($(this));
var mdlCtrl = member.data("$ngModelController");
if(!mdlCtrl){
throw "Group member should have ng-model";
}
ctrls.push(mdlCtrl);
});
var errKey = attrs['name']+"GrpReqd";
var min = attrs['minRequired'] || 1;
var max = attrs['maxRequired'] || ctrls.length;
$scope.validateGroup = function(){
var defined=0;
for(i=0;i<ctrls.length;i++){
if(ctrls[i].$modelValue){
defined++;
}
}
if(defined < min || defined > max){
formCtrl.$setValidity(errKey,false);
} else {
formCtrl.$setValidity(errKey,true);
}
};
//support real time validation
angular.forEach(ctrls,function(mdlCtrl){
$scope.$watch(function () {
return mdlCtrl.$modelValue;
}, $scope.validateGroup);
});
}
};
})
HTML usage :
<div name="CancellationInfo" group min-required="1" max-required="1">
<input type="text" class="form-control group-member" style="width:100%;" name="Field1" ng-model="data.myField" />
<input type="text" class="form-control group-member" style="width:100%;" name="Field1" ng-model="data.myField2" />
<input type="text" class="form-control group-member" style="width:100%;" name="Field2" ng-model="data.myField3" />
</div>
Here group directive identifies the logical grouping. This directive sits on an element without ng-model, a div in the above example. group directive receives 2 optional attribute min-required and max-required. Group members are identified using group-member class on individual fields. Group members are supposed to have an ng-model for binding. Since group directive doesn't have an ng-model error will be emitted under yourForm.$error.CancellationInfoGrpReqd in the above case. Unique Error key is generated from the element name on which group directive is sitting with GrpReqd appended to it.

KnockoutJS Bind checkbox visibility to checkbox being checked OR having a certain value

So I have a checkbox, and I'm trying to implement the following logic to set the visibility:
If checkbox is checked OR the checkbox's value is below a specified number, set visible = true.
If the value exceeds the test value AND the checkbox is not checked, hide it.
Here is what I have so far:
<input type="checkbox" data-bind="visible: $data.Cost <= $root.itemLevel() - $root.totalEnchantLevelsUsed() || checked" />
I have tried several variations of getting 'checked', including changing 'checked' to $root.isChecked:
this.isChecked = ko.computed ( function (item) {
console.log('item', item); // PURELY TO TEST THE VALUE
}
But that is telling me that 'item' is undefined. When I try to explicitly pass in $data, I get an error message about ko.computed and having to set 'write' access.
Is there not a relatively simple way to do this that I'm just overlooking? Admittedly I'm not super familiar with knockout.
Here is something similar to what you're trying to do: http://jsfiddle.net/2aXrJ
Html:
<div data-bind="foreach:items">
<label data-bind="visible: isAllowedInWorkflow">
<input data-bind="value: val" type="checkbox" />
This checkbox has value
<span data-bind="text:val"></span>
</label>
</div>
jS:
ko.applyBindings({
items: [createItem(10), createItem(20), createItem(30) ]
})
function createItem(val) {
var _item = {
val: val
,isSelected: ko.observable(false)
};
_item.isAllowedInWorkflow = ko.computed(function() {
//notice the order is importeant since you always want isSelected to be triggered for the
//computed to calculate its dependencies
return !_item.isSelected() && val > 10;
});
return _item;
}

knockout js if statement to Display value based on boolean data type

I am trying to Display a value based on a table value of True or False. For example if the Value is True then I want it to Say Supported and If it's False then I want it to Say Not Supported! This is my html code
<p><input type="text" data-bind="value: Support" /></p>
Java script Code
$(function() {
dm.viewModel = function() {
var clients = ko.observableArray(),
selectedClient = ko.observable(),
clientChanged = function() {
$.getJSON(dm.WebServices + "/dm/get/clientinfo?client=" + encodeURIComponent(selectedClient()), function(data) {
if (data != null) {
dm.viewModel.Name(selectedClient());
dm.viewModel.Support(data[0]['Support']);
}
})
$('#divClientData').show();
},
LoadClients = function() {
$('#divClientData').hide();
$.getJSON(dm.WebServices + "/dm/get/clientlist", function(data) {
$.each(data, function(key, val) {
clients.push(val);
});
});
},
Name = ko.observable(),
Support = ko.observable(),
return {
Name: Name,
Support: Support
};
}();
ko.applyBindings(dm.viewModel);
dm.viewModel.LoadClients();
})
In this kind of case you can evaluate the property and render based on the value. Even a function can be provided inside the binding. You can use this:
<input type="text" data-bind="value: Support() ? 'Supported' : 'Not Supported'" />
You can do that with the if binding
See documentation here
Example from the docs:
<label><input type="checkbox" data-bind="checked: displayMessage" /> Display message</label>
<div data-bind="if: displayMessage">Here is a message. Astonishing.</div>
So for you
<div data-bind="if: Support">Supported</div>
<div data-bind="ifnot: Support">Not Supported</div>
Edit: The other answers suggesting using the value binding with a ternary condition are probably a better way to accomplish this. I'll keep this up as a reference, but I recommend that solution.
What you're looking for, in this case, is ko.computed().
EDITED: (Support appears to be in-use as a value from the data set)
Add a new value to your ViewModel, something like this:
IsSupported = ko.computed(function(){
if(this.Support() == true){
return "Supported";
} else {
return "Not Supported";
}
}, this)
Then, in your markup, you will have to change your data-bind just slightly:
<p><input type="text" data-bind="value: IsSupported" /></p>
Alternatively, if you don't want to change your Support field, you'll have to do something like this in your HTML, as suggested by other commenters:
<p><input type="text" data-bind="value: (Support() ? 'Supported' : 'Not Supported')" /></p>
I'd recommend the former, however, as really, you should keep that logic tucked away inside your ViewModel.
(See the KO docs for more info on computed: http://knockoutjs.com/documentation/computedObservables.html)
In my work I use KO boolean conditions like this:
<div id="bla" data-bind="visible: position != value"></div>
KO is very useful for those types of problems.

Categories

Resources