I'm having a problem with the knockout.js library. I am using the following code, and the databindings are not executing properly.
HTML Code:
<form data-bind="submit: LogintoSite">UserId:
<input type="email" data-bind="value: UserLogin" />Password:
<input type="password" data-bind="value: Password" />
<button type="submit">Login</Button>
</form>
JavaScript:
var LoginScreenViewModel = function () {
var self = this;
self.UserLogin = ko.observable("Hello");
self.Password = ko.observable("");
self.LoginToSite = function () {
alert("You Pushed the button");
};
};
ko.ApplyBindings(new LoginScreenViewModel());
The project itself is in MVC 4 but i have tried this code on jsfiddle as well and it does not work there either. I can't figure out why it will not work. I am assuming this is something simple i forgot in my code.
Thanks!
You have LoginToSite in your viewmodel while in your databindings you have LogintoSite, notice the lowercase "t".
As somebody else mentioned in the comments I think you should also be calling applyBindings instead of ApplyBindings
Related
learning Angular, met another issue in my way, hope anyone can help.
I've got one button that must perform two actions: download something and send formdata to the server. So I've wrote this:
<form id='download'>
<label for='name'>Name:</label>
<input type='name' ng-model='nameValue'>
<label for='email'>Email:</label>
<input type='email' id='email' ng-model='emailValue'>
</form>
<a ng-click='sendFormDataIfVal()' href="{{filename}}" download="{{filename}}">Download</a>
But the problem and my question is - now downloading and sending occur simultaneously while I wanna download file only if emailValue pass validation and nameValue is not empty. Suppose it's gonna be something like this, but I dunno how to complete function
$scope.sendFormDataIfVal = function() {
$scope.validateEmail() && $scope.sendFormData(); // download & send
if(!$scope.validateEmail()) {
// do not download and do not send
}
};
Any advise will be greatly... u know :)
One approach is to disable the link using css.
once enabled, both the click event handler and the native download function will work.
toggle the link's 'disabled' css class via a validation function
here is a working example
HTML
<body ng-app="myApp" ng-controller="myController">
<form id="download">
<label for="name">Name:</label>
<input type="name" ng-model="nameValue" />
<label for="email">Email:</label>
<input type="email" id="email" ng-model="emailValue" />
</form>
<a ng-class="{'disabled' : !isFormValid()}" ng-click="sendFormData()" ng-href="{{fileUrl}}" download="{{fileName}}" >Download</a>
</body>
JS
var myApp = angular.module('myApp',[]);
myApp.controller('myController', ['$scope', function($scope) {
$scope.emailValue = 'sample#email.com';
$scope.nameValue = "";
$scope.fileUrl = "http://thatfunnyblog.com/wp-content/uploads/2014/03/funny-videos-funny-cats-funny-ca.jpg";
$scope.fileName = "funny-cat.jpeg";
$scope.isEmailValid = function(){
//replace this simplified dummy code with actual validation
return $scope.emailValue.indexOf('#') !== -1;
}
$scope.isFormValid = function(){
return $scope.isEmailValid() && $scope.nameValue.length;
}
$scope.sendFormData = function(){
console.log('sent that data');
}
}]);
CSS
a.disabled{
/*simulate disabled using css, since this property is nto supported on anchor element*/
color:gray;
pointer-events:none;
}
Try this:
$scope.sendFormDataIfVal = function() {
if(!$scope.validateEmail()) {
// do not download and do not send
}
else{
download and send
}
};
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>
Im trying to make a website which makes searches easy for me.
I want to be able to write any text in a text box, and make a java script generate the appropriate links.
Ive been trying this:
function prepare_link() {
var url_param = document.getElementById('url_param');
var target_link = document.getElementById('target_link');
if ( ! url_param.value ) {
return false;
}
target_link.href = target_link.href + escape(url_param.value);
}
<input type="text" name="url_param" id="url_param" onkeypress='prepare_link()' onKeyUp='prepare_link()' />
<input type="button" onclick="prepare_link();" value="Generate" /><br>
Google<br>
Bing
For some reason the search string is repeated, but i would like it to update links for each keypress and not just when i hit the generate button.
Moreover the second links isn't being updated :(
Any ideas? :)
Please have a look of the following code snippet, hope this will help to resolve your Issue.
In the following snippet you will not get the repeated values. Also, it will work with 'keyup' and 'click' event :
var google = "https://www.google.dk/search?q=";
function prepare_link() {
var target_link = document.getElementById('target_link');
target_link.href = google + escape(url_param.value);
alert(target_link.href);
}
void function () {
document.addEventListener("keyup", function(e) {
prepare_link();
e.preventDefault();
});
var click = document.getElementById("target_link");
click.addEventListener("click", function() {
document.dispatchEvent(keyEvent);
});
}();
<input type="text" name="url_param" id="url_param" value=""/>
<input type="button" value="Generate" onclick="prepare_link();" /><br>
Google<br>
Thanks :)
Simplified code below. I have another build w/ajax calls that I know are working b/c I can see them hit the server. But I cannot get the stuff to render the changes back to the UI.
.html:
<div id="LoginPage" data-title="LoginPage" data-role="page" data-theme="a">
<div data-role="content" class="minimalPaddingContent">
<div class="divDivider"></div>
<h3>REACH Energy Audit Login</h3>
<input type="text" placeholder="User Name" id="userName" data-bind="value: successOrFailureSw"/>
<input type="password" placeholder="Password" id="password"/>
Sign In
<span data-bind="text: successOrFailureSw"></span>
</div>
.js:
var LoginViewModel = function (commonName, successOrFailureSw) {
var self = this;
self.commonName = ko.observable(commonName);
self.successOrFailureSw = ko.observable(successOrFailureSw);
self.changeValue = function(){
console.log("changed!");
self.successOrFailureSw = "new value!";
}
};
ko.applyBindings(new LoginViewModel("", "super fail"));
I am pretty sure my mappings are correct on the .html b/c the original value will render as super fail, and if I change the value in the text box that maps to "successOrFailureSw", I get the updated value in the span tag, but I cannot get a change of effect at click time for the login button.
I know that I am missing something so simple, so I apologize in advance.
Thanks!
brian
You assign value to the observable in wrong way. Each obserbable is a function so you should call it using () modify your changeValue function to the following:
self.changeValue = function(){
console.log("changed!");
self.successOrFailureSw("new value!");
}
You should set the value like this:
self.successOrFailureSw('new value!');
successOrFailureSw is not a string. That's why you need to set it in the same fashion that you did earlier in your code.
Try this :
self.successOrFailureSw("new value!")
Does anyone know if it is possible to generate the viewmodel for knockoutjs automatically.
1) I have (for example) the following html code:
<input type="text" data-bind="value: XYZ" />
<input type="text" data-bind="value: ABC" />
<input type="text" data-bind="value: Prop1" />
2) Then I need to create a viewmodel like this:
function ViewModel()
{
this.XYZ = ko.observable();
this.ABC = ko.observable();
this.Prop1 = ko.observable();
}
I would like to skip step 2, because I already defined the properties which should be available in the html-markup (sort of).
update:
As mentioned in the comments, there would be drawbacks to do such a thing. (That's probably the reason it is not supported by knockoutjs). I will take a different approach, but nevertheless I made a simple Javascript function which can generate a ViewModel out of a VERY simple markup. If anyone is interested, that's what I came up with:
function getViewModelFromView(selector) {
var vm = {};
$("[data-bind]", selector).each(function () {
var attribute = $(this).attr("data-bind");
if (attribute.indexOf(':') > 0) {
vm[attribute.slice(attribute.indexOf(':')+1).trim()] = ko.observable();
}
});
return vm;
}