I have an input textbox and whenever it loses focus I want to get its value text in a function.
For example, if type "testimonials1", how could I get that text in an event handler for the blur event?
This is what I tried. I get ProjectTestimonial as an object, not user-typed text.
HMTL
<div class="ratingcontents" data-bind="foreach: ProjectTestimonial">
<!--ko if: !Testimonialstext-->
<input type="text" placeholder="Testimonials" class="txttestimonials"
data-bind="
text: Testimonialstext,
event: {
blur: $root.testimonialblurFunction.bind(SourceId, SourceText, Testimonialstext)
}
"
>
<!--/ko-->
</div>
JS
self.testimonialblurFunction = function (data, event, Testimonialstext) {
debugger;
alert(data.soid + Testimonialstext);
}
You can use event, that attaches to any JS event:
<input name="id" data-bind="value: id, event: { blur: blurFunction }">
And in your view model:
self.blurFuncion = function(){
// this attacks when blur event occurs in input
}
Simple as that.
The first mistake you made was using the 'text' binding on the input field, rather than the 'value' binding.
Regarding the event handler, I would not do this. I would use knockout's 'subscribe' functionality to listen for changes to the observable.
Here is a Jsfiddle version of your code. I have changed your markup to demonstrate more clearly.
HTML
<div class="ratingcontents" data-bind="foreach: ProjectTestimonial">
<input type="text" placeholder="Testimonials" class="txttestimonials"
data-bind="value: Testimonialstext" />
</div>
Javascript
function viewModel(jsModel){
var self = this;
self.ProjectTestimonial = ko.utils.arrayMap(jsModel, function(item) {
return new testimonial(item);
});
}
function testimonial(jsTestimonial){
var self = this;
ko.mapping.fromJS(jsTestimonial, {}, self);
self.Testimonialstext.subscribe(function(){
alert(self.SourceId() + self.Testimonialstext());
});
}
var rawModel = [
{
SourceId: '1',
SourceText: 'Foo',
Testimonialstext: 'Ahoy there.'
},
{
SourceId: '2',
SourceText: 'Bar',
Testimonialstext: 'Blah blah blah'
}];
ko.applyBindings(new viewModel(rawModel));
Use the has focus binding instead. From what I understand you want the data in the text box once the user stops editing. This is simple enough. Check out this example from the knockout js documentation page.
<p>
Hello <b data-bind="text:name"></b> </p>
<input data-bind="value: name, hasfocus: editing" />
<p><em>Click the name to edit it; click elsewhere to apply changes.</em></p>
View model
function PersonViewModel(name) {
// Data
this.name = ko.observable(name);
this.editing = ko.observable(false);
// Behaviors
this.edit = function() { this.editing(true) }
}
ko.applyBindings(new PersonViewModel("Bert Bertington"));
jsFiddle
Related
I want to enable/disable a kendo combobox based on the user's selection from a checkbox, which I am storing in a variable.
I already tried setting the variable to the enable property, but this is useful only when the control is being built-in.
Does anybody know If I can do this while creating the control?
<div id="fund" class="col-xs-3">
input class="required" data-bind="title: $parent.selectedFund,
kendoComboBox: {
placeholder: 'Start typing to search...',
value: $parent.test,
widget: $parent.searchSource,
dataTextField: 'managerName',
dataValueField: 'managerId',
filter: 'contains',
autoBind: false,
minLength: 3,
enable: overrideGlobalMapping, //this does not work for me even though the variable holds the correct value
change: function(){ if(this.value() && this.selectedIndex == -1)
{
setTimeout(function () {$parent.selectedManagerId(null);}, 100);}},
dataSource: {
serverFiltering: true,
transport: {
read: $parent.retrieveManager
}
}
}" />
</div>
I ended up wrapping the kendo combox definition in a function, so it now looks likes this:
<input type="checkbox" id="overrideGlobalMappingCheck" onclick="SetFundsCombobox()" data-bind="checked: overrideGlobalMapping, enable: $root.canConfirmMapping" />
The kendo combobox is still wrapped and has an id, which I later use to manipulate it in javascript:
<div class="col-xs-3" id="funds">
<input class="required" data-bind="title: $parent.selectedFund,
kendoComboBox: {
placeholder: 'Start typing to search...',
value: $parent.selectedManagerId,
...
}" />
</div>
And this is the JavaScript function bound to the onclick checkbox's event:
function SetFundsCombobox() {
var fundsDiv = document.getElementById('funds');
var inputSelector = fundsDiv.getElementsByClassName('k-input');
var span = fundsDiv.getElementsByTagName('span');
if (document.getElementById('overrideGlobalMappingCheck').checked) {
document.getElementById('funds').disabled = false;
inputSelector[0].disabled = false;
span[1].classList.remove("k-state-disabled");
} else {
document.getElementById('funds').disabled = true;
inputSelector[0].disabled = true;
span[1].classList.add("k-state-disabled");
}
};
I'd have rather preferred to perform this via the view model, but it works for now.
EDIT:
I've been able to do this the right way (following the MVVM pattern), so now rather than wrapping the kendo combo box in a function, I added the following function in the view model:
$scope.overrideGlobalMappingChecker = ko.computed(function () {
if ($scope.entityMapping()) {
var checkboxChecked = $scope.entityMapping().overrideGlobalMapping();
$("#funds .k-input").prop('disabled', !checkboxChecked);
if (!checkboxChecked) {
$scope.selectedFundId(null);
}
}
});
So now, what the html only needs is the definition of the id in the div containing the combo box:
<div class="col-xs-3" id="funds">
<input data-bind="title: $parent.selectedFundName, kendoComboBox: {
autoBind: false,
...
}" />
</div>
And that's it, it's a much cleaner/correct way to handle this.
I've got a ko.observable in my viewmodel, which is attached to an input. When user changes value of that input (per-character) I run AJAX call, which downloads suggestions from backend.
When user chooses one of suggestions, I'd like to fill the input with chosen value, but without sending the AJAX call. But setting observable's value will still trigger event and call function attached to textInput binding.
How can I set observable's value without triggering textInput?
Sample code:
var name = ko.observable();
name.subscribe(nameChanged);
var nameChanged = function() {
someService.post(name(), success, failure);
}
var someAction = function() {
name("Test"); // I don't want to trigger AJAX call here
}
<input type="text" data-bind="textInput: name" />
Another option is to use a computed observable as an intermediary. The ajax function can trigger in the write event of the computed so that direct writes to the observable bypass it.
function viewModel(){
var self = this;
self.realName = ko.observable('test');
self.Name = ko.computed({
read: function(){
return self.realName();
},
write: function(value){
self.realName(value);
nameChanged(value);
}
});
function nameChanged(newName) {
console.log("name changed:", newName);
}
self.modifyName = function(){
self.realName(self.realName() + 'z');
}
}
ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<input type="text" data-bind="textInput: Name" />
<br />
<button data-bind="click: modifyName">Modify</button>
Maybe set a particular CSS class on the field after the selection is made and put some logic around the ajax call to check if the field has the CSS class.
Instead of subscribing to the change event of the observable you could tie your ajax call to the change event of the ui element instead. You would get rid of name.subscribe(nameChanged); and add an event binding:
data-bind="textInput: name, event: { changed: nameChanged }"
An "old fashioned" way that works, but is not really elegant, is to temporarily dispose the subscription and then reattach it:
var myName = ko.observable();
var nameSub = myName.subscribe(nameChanged);
function nameChanged(newName) {
console.log("name changed:", newName);
}
function changeWithoutLog() {
nameSub.dispose();
myName("Test");
nameSub = myName.subscribe(nameChanged);
}
ko.applyBindings({ name: myName });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<input type="text" data-bind="textInput: name" />
<button data-bind="click: changeWithoutLog">change without post</button>
Well in other cases i will get datepicker binded to my textbox which will be straight forward but not in this case .
Fiddle link : http://jsfiddle.net/JL26Z/1/ .. while to setup perfect seanrio i tried but unable to bind datepicker to textboxes . except that everything is in place
My code :
**<script id="Customisation" type="text/html">** // here i need to have text/html
<table style="width:1100px;height:40px;" align="center" >
<tr>
<input style="width:125px;height:auto;" class="txtBoxEffectiveDate" type="text" id="txtEffective" data-bind="" />
</tr>
</script>
The above code is used for my dynamic generation of same thing n no of time when i click each time on a button . So above thing is a TEMPLATE sort of thing .
My knockout code :
<div data-bind="template:{name:'Customisation', foreach:CustomisationList},visible:isVisible"></div>
<button data-bind="click:$root.CustomisatioAdd" >add </button>
I tried same old way to bind it with datepicker
$('#txtEffective').datepicker(); // in document.ready i placed
Actually to test this i created a textbox with some id outside script with text/html and binded datepicker to it and It is working fine sadly its not working for the textbox inside text/html and i want to work at any cost.
PS: well i haven't posted my view model as it is not required in this issue based senario
View model added with Js
var paymentsModel = function ()
{
function Customisation()
{
var self = this;
}
var self = this;
self.isVisible = ko.observable(false);
self.CustomisationList = ko.observableArray([new Customisation()]);
self.CustomisationRemove = function () {
self.CustomisationList.remove(this);
};
self.CustomisatioAdd = function () {
if (self.isVisible() === false)
{
self.isVisible(true);
}
else
{
self.CustomisationList.push(new Customisation());
}
};
}
$(document).ready(function()
{
$('#txtEffective').datepicker();
ko.applyBindings(new paymentsModel());
});
Any possible work around is appreciated
Regards
The best way I've found to do this is create a simple bindingHandler.
This is adapted from code I have locally, you may need to tweak it...
** code removed, see below **
Then update your template:
** code removed, see below **
By using a bindingHandler you don't need to try to hook this up later, it's done by knockout when it databinds.
Hope this is helpful.
EDIT
I created a fiddle, because I did indeed need to tweak the date picker binding quite a lot. Here's a link to the Fiddle, and here's the code with some notes. First up, the HTML:
<form id="employeeForm" name="employeeForm" method="POST">
<script id="PhoneTemplate" type="text/html">
<div>
<span>
<label>Country Code:</label>
<input type="text" data-bind="value: countryCode" />
</span>
<span><br/>
<label>Date:</label>
<input type="text" data-bind="datepicker: date" />
</span>
<span>
<label>Phone Number:</label>
<input type="text" data-bind="value: phoneNumber" />
</span>
<input type="button" value="Remove" data-bind="click: $parent.remove" />
</div>
</script>
<div>
<h2>Employee Phone Number</h2>
<div data-bind="template:{name:'PhoneTemplate', foreach:PhoneList}">
</div>
<div>
<input type="button" value="Add Another" data-bind="click: add" />
</div>
</div>
</form>
Note I removed the id=... from in your template; because your template repeats per phone number, and ids must be unique to be meaningful. Also, I removed the datepicker: binding from the country code and phone number elements, and added it only to the date field. Also - the syntax changed to "datepicker: ". If you need to specify date picker options, you would do it like this:
<input type="text" data-bind="datepicker: myObservable, datepickerOptions: { optionName: optionValue }" />
Where optionName and optionValue would come from the jQueryUI documentation for datepicker.
Now for the code and some notes:
// Adapted from this answer:
// https://stackoverflow.com/a/6613255/1634810
ko.bindingHandlers.datepicker = {
init: function(element, valueAccessor, allBindingsAccessor) {
//initialize datepicker with some optional options
var options = allBindingsAccessor().datepickerOptions || {},
observable = valueAccessor(),
$el = $(element);
// Adapted from this answer:
// https://stackoverflow.com/a/8147201/1634810
options.onSelect = function () {
if (ko.isObservable(observable)) {
observable($el.datepicker('getDate'));
}
};
$el.datepicker(options);
// set the initial value
var value = ko.unwrap(valueAccessor());
if (value) {
$el.datepicker("setDate", value);
}
//handle disposal (if KO removes by the template binding)
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$el.datepicker("destroy");
});
},
update: function(element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor()),
$el = $(element);
//handle date data coming via json from Microsoft
if (String(value).indexOf('/Date(') === 0) {
value = new Date(parseInt(value.replace(/\/Date\((.*?)\)\//gi, "$1")));
}
var current = $el.datepicker("getDate");
if (value - current !== 0) {
$el.datepicker("setDate", value);
}
}
};
function Phone() {
var self = this;
self.countryCode = ko.observable('');
self.date = ko.observable('');
self.phoneNumber = ko.observable('');
}
function PhoneViewModel() {
var self = this;
self.PhoneList = ko.observableArray([new Phone()]);
self.remove = function () {
self.PhoneList.remove(this);
};
self.add = function () {
self.PhoneList.push(new Phone());
};
}
var phoneModel = new PhoneViewModel();
ko.applyBindings(phoneModel);
Note the very updated binding handler which was adapted from this answer for the binding, and this answer for handling onSelect.
I also included countryCode, date, and phoneNumber observables inside your Phone() object, and turned your model into a global variable phoneModel. From a debugger window (F12 in Chrome) you can type something like:
phoneModel.PhoneList()[0].date()
This will show you the current value of the date.
I notice that your form is set up to post somewhere. I would recommend instead that you add a click handler to a "Submit" button and post the values from your phoneModel using ajax.
Hope this edit helps.
Dynamic entities need to have datepicker applied after they are created. To do this I'd use an on-click function somewhere along the lines of
HTML
<!-- Note the id added here -->
<button data-bind="click:$root.CustomisatioAdd" id="addForm" >add </button>
<script>
$(document).on('click', '#addForm', function(){
$('[id$="txtEffective"]').datepicker();
});
</script>
I am trying to store value in attribute in input tag which would like as follows.
The following code will repeat several times and the value for different radio can be saved using index.
<div data-bind="attr : { name : 'ex['+$index()+']' }>
<input type="radio" name="value" data-target="#modal" data-bind="click:fun.fill($index())"/>
</div>
From the above text box i can get the index of that input.And it points to a common modal function from bootstrap which opens a popup.
<div class="modal fade">
<select data-bind="attr:{name:'assignedResources['+$index()+'][repeatedType]'},
options : $root.repeats,value : repeatedType"></select>
</div><!-- /.modal -->
This is a sample of modal target.I want to call this modal as common.(i.e)it will be called from several places.I want to show appropriate popup for appropriate click from radio button.
But what i get is value of last index.Thats my problem
I'm not 100% sure I understand your question, but something like this...
this.abc = ko.observable('');
this.fun = {
var that = this;
fill: function(index) {
console.log(that.abc());
}
}
As far as I understand your problem, you need an observable to store your value, and then you can access it by any other function on your viewModel.
This is a jsFiddle with my initial approach, let me know if is what you needed or clarify instead:
http://jsfiddle.net/rdarioduarte/X8Rc4/
With a model like this:
var viewModel = function() {
this.abc = ko.observable('Value to store');
this.fun = function() {
alert(this.abc());
}
}
ko.applyBindings(new viewModel());
Thanks,
Dario
I do not quite understand about your question. But, maybe this may help:
1) Obtains index of your input element automatically on page load to viewModel function maybe need custom binding to handle that:
e.g custom binding:
ko.bindingHandlers.saveIndex = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var index = ko.utils.unwrapObservable(valueAccessor());
viewModel.fun(index); // accessing fun function on viewModel
// You can also access that function using bindingContext.$root
// bindingContext.$root.fun(index);
}
};
e.g html:
<input type="text" data-bind="saveIndex: $index()"/>
2) Store index to input value attribute using attr binding:
<input type="text" data-bind="attr: { value: $index() }">
3) Send your input attr value to viewModel function onClick:
<input type="text" value="thisIsExampleValue" data-bind="click: function() { $root.fun($element.value); }">
You also can use event binding for this behavior, Knockout.Event-binding
UPDATE:
Try this:
<div data-bind="attr : { name : 'ex['+$index()+']' }>
<input type="radio" name="value" data-target="#modal" data-bind="click: function() { fun.fill($index()) }"/>
I'm trying to get my head around Knockout.js and I'm quite stuck when it comes to checkboxes.
Server side I'm populating a set of checkboxes with their corresponding values. Now, when any of the unchecked checkboxes are checked, I need to store it's value in a comma-seperated string. When they're unchecked, the value needs to be deleted from the string.
Have anyone got a hint on how to achieve this with knockoutjs?
I have the following code so far:
ViewModel:
$().ready(function() {
function classPreValue(preValue)
{
return {
preValue : ko.observable(preValue)
}
}
var editOfferViewModel = {
maxNumOfVisitors : ko.observable(""),
goals : ko.observable(""),
description : ko.observable(""),
contact : ko.observable(""),
comments : ko.observable(""),
classPreValues : ko.observableArray([]),
addPreValue : function(element) {
alert($(element).val());
this.classPreValues.push(new classPreValue(element.val()));
}
};
ko.applyBindings(editOfferViewModel);
});
And my checkboxes are populated with a foreach loop:
<input data-bind="checked: function() { editOfferViewModel.addPreValue(this) }"
type="checkbox" checked="yes" value='#s'>
#s
</input>
I try to pass the checkbox element as the parameter to my addPreValue() function, but nothing seems to happen when I check the checkbox?
Any help/hints on this is greatly appreciated!
The checked binding expects to be passed a structure that it can read/write against. This could be a variable, an observable, or a writable dependentObservable.
When passed an array or observableArray, the checked binding does know how to add and remove simple values from the array.
Here is a sample that also includes a computed observable that contains the array as comma delimited values. http://jsfiddle.net/rniemeyer/Jm2Mh/
var viewModel = {
choices: ["one", "two", "three", "four", "five"],
selectedChoices: ko.observableArray(["two", "four"])
};
viewModel.selectedChoicesDelimited = ko.computed(function() {
return this.selectedChoices().join(",");
}, viewModel);
ko.applyBindings(viewModel);
HTML:
<ul data-bind="template: { name: 'choiceTmpl', foreach: choices, templateOptions: { selections: selectedChoices } }"></ul>
<script id="choiceTmpl" type="text/html">
<li>
<input type="checkbox" data-bind="attr: { value: $data }, checked: $item.selections" />
<span data-bind="text: $data"></span>
</li>
</script>
Why isn't there a Mutually exclusive checkboxes example Online somewhere
Since this link came up first whilst I was searching for mutually exclusive checkboxes I will share my answer here. I was banging my head against the wall with all my attempts. By the way, when you handle the click event in a binding in-line knockoutjs it seems to disconnect the bindings(maybe only because I tried to call my resetIllnesses function as defined below) even if you return true from the function. Maybe there is a better way but until then follow my lead.
Here is the type I needed to bind.
var IllnessType = function (name,title) {
this.Title = ko.observable(title);
this.Name = ko.observable(name);
this.IsSelected = ko.observable(false);
};
The array to bind with.
model.IllnessTypes = ko.observableArray(
[new IllnessType('IsSkinDisorder', 'Skin Disorder'),
new IllnessType('IsRespiratoryProblem', 'Respiratory Problem'),
new IllnessType('IsPoisoning', 'Poisoning'),
new IllnessType('IsHearingLoss', 'Hearing Loss'),
new IllnessType('IsOtherIllness', 'All Other Illness')]
);
The reset illness function to clear them all.
model.resetIllnesses = function () {
ko.utils.arrayForEach(model.IllnessTypes(), function (type) {
type.IsSelected(false);
});
};
The markup
<ul data-bind="foreach:IllnessTypes,visible: model.IsIllness()">
<li><label data-bind="html: Title"></label></li>
<li><input class="checkgroup2" type="checkbox"
data-bind="attr:{name: Name },checked:IsSelected" /></li>
</ul>
This just doesn't work
If you have been struggling with trying to call the resetIllness function as I below, you will feel my pain.
<input type='checkbox' data-bind="checked:IsSelected,
click: function() { model.resetIllnesses(); return true; }" />
you have been sharing my pain. Well, it works! when you call it from following example.
Notice that there is a class that I added above so that I can add the click function.
The script that makes all your problems go away.
<script type="text/javascript">
$(function() {
$(".checkgroup2").on('click', function() {
model.resetIllnesses();
var data = ko.dataFor(this);
data.IsSelected(true);
});
});
</script>
Send info to the server
Also, in my case I had to send the information up to the server differently than the default html format so I changed the inputs a little.
<input class="checkgroup2" type="checkbox" data-bind="checked:IsSelected" />
<input type="hidden" data-bind="attr:{name: Name },value:IsSelected" />