I am currently developing using ASP.NET, and I'd like to get started on Knockout JS... Basically what I've done is I've copy-pasted the code provided in the first tutorial.
So I put this into my head:
<script type="text/javascript">
function() {
// This is a simple *viewmodel* - JavaScript that defines the data and
behavior of your UI
function AppViewModel() {
this.firstName = ko.observable("Bert");
this.lastName = ko.observable("Bertington");
this.fullName = ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this);
this.capitalizeLastName = function() {
var currentVal = this.lastName(); // Read the current value
this.lastName(currentVal.toUpperCase()); // Write back a modified value
};
}
// Activates knockout.js
ko.applyBindings(new AppViewModel());
}();
</script>
...along with
<script type="text/javascript" src="Scripts/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="Scripts/knockout-2.0.0.js"></script>
In my body I placed
<!-- This is a *view* - HTML markup that defines the appearance of your UI -->
<p>
First name: <strong data-bind="text: firstName"></strong>
</p>
<p>
Last name: <strong data-bind="text: lastName"></strong>
</p>
<p>
First name:
<input data-bind="value: firstName" /></p>
<p>
Last name:
<input data-bind="value: lastName" /></p>
<p>
Full name: <strong data-bind="text: fullName"></strong>
</p>
<button data-bind="click: capitalizeLastName">
Go caps</button>
The code was all taken from Knockout JS's tutorial, but somehow the values don't bind themselves automatically--in other words it doesn't work for me. Am I missing something here?
It looks to me like you JavaScript code is being executed before the DOM (your HTML) has been rendered. The JavaScript function you have included in the head is executed immediately. You need to ensure that this code is only executed when the page has been fully rendered.
You can do that with the jQuery ready function.
<script type="text/javascript">
$(document).ready(function () {
// your existing JavaScript goes here.
})
</script>
It's seems to me that You wrongly use anonymous function wrapper.
You need to add more ( ) to code.
(function() {
...
})();
Working example: http://jsfiddle.net/AlfeG/bZatD/
If you didn't want to use jQuery, You could also:
remove your outer self-executing function
put the script referencing knockout view models at the bottom of the body
Related
in my site i have google reCaptcha component which allows me to specify a callback function inside the attribute "data-callback".
this is my html file:
<html>
<script src='https://www.google.com/recaptcha/api.js'></script>
<script type="text/javascript">
var txtClientResponse = document.getElementById('txtClientResponse');
var txtServerResponse = document.getElementById('txtServerResponse');
function successCallback(value) {
this.txtClientResponse.value = value;
this.txtServerResponse.innerText.clear();
}
</script>
<body>
<div class="g-recaptcha" data-callback="successCallback" data-error-callback="errorCaptcha" data-sitekey="xxxxxx" />
<input ID="txtClientResponse" />
<input ID="txtServerResponse" />
</body>
Everything works great except the fact that i can not access the local variable txtClientResponse, that holds a DOM element, from the callback function "successCallback". to local variables like var test = 1, i can access using this.test.
i tried to pass the "this" using like i am doing on Angular but it didn't work. i need a pure javascript solution - not angular:
<div class="g-recaptcha" data-callback="successCallback.bind(this)" data-error-callback="errorCaptcha" data-sitekey="xxxxxx"/>
I didn't use pure JavaScript for long time because i am using Angular, i forgot that the script tag with the javascript code should be at the very bottom of the body tag content or at least to assign the variables with the getElementById inside the document.onreadystatechange event.
The problem was that the lines:
var txtClientResponse = document.getElementById('txtClientResponse');
var txtServerResponse = document.getElementById('txtServerResponse');
executed before the HTML elements where ready.
Here is the fix for users that may find this question using google
<html>
<body>
<div class="g-recaptcha" data-callback="successCallback" data-error-callback="errorCaptcha" data-sitekey="xxxxxx" />
<input ID="txtClientResponse" />
<input ID="txtServerResponse" />
<script src='https://www.google.com/recaptcha/api.js'></script>
<script type="text/javascript">
var txtClientResponse = document.getElementById('txtClientResponse');
var txtServerResponse = document.getElementById('txtServerResponse');
function successCallback(value) {
this.txtClientResponse.value = value;
this.txtServerResponse.innerText.clear();
}
</script>
</body>
</html>
For a few hours I've been trying to understand what's wrong. My purpose is to enable a button after textfields are filled. Code seems fine according to my test at JSFiddle but it's still not working on my server. Am'I missing something or is this a server problem (which is hard to believe since javascript is client-side)?
PS: I'm not expert at HTML, so I don't know how to identate it's syntax; if it's not that readable I'm sorry and would appreciate an edit-help. thanks.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="css/style.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript">
var $input = $('input:text'),
$apply = $('#apply');
$apply.attr('disabled', true);
$input.keyup(function() {
var trigger = false;
$input.each(function() {
if (!$(this).val()) {
trigger = true;
}
});
trigger ? $apply.attr('disabled', true) : $apply.removeAttr('disabled');
});
</script>
</head>
<body>
<section class="container">
<div class="OpenKore">
<div id="absolute">
<form method="GET" action="generate.php">
<fieldset>
<legend><h1>OpenKore Automatic Config:</h1></legend>
LOGIN:
<p><input type="text" id="id_login" name="login_value" value="" placeholder="Login"></p>
SENHA:
<p><input type="text" id= "id_senha" name="senha_value" value="" placeholder="Senha"></p>
PIN:
<p><input type="text" id="id_pin" name="pin_value" value="" placeholder="PIN"></p>
<input id="apply" type="submit" name="commit" disabled value="Gerar Configurações">
</fieldset>
</form>
</div>
</div>
</section>
</body>
</html>
When the browsers reads your HTML page, it reads top to bottom. When it gets to your <script> tags it runs them. Now it us doing this before it has got to the rest of the page, i.e. before it even knows about any body or form or input:text tags, so even though you code will run, it will simply not do anything because none of the elements on the page exist yet.
JavaScript 101, make the code run after the page has loaded, if you need to access elements on the page. How do you do that? either put the code at the bottom of the page (move your <script> tags to just before the </body> tag), or wrap your code in a function that is executed after the browser has finished loading the page. Now jQuery has a very helpful way of doing this for you, pass a function to jQuery and it will be executed after the page is loaded.
jsFiddle does this automatically for you, hence the drop down in the top left corner saying 'onLoad'
i.e. your code
$(); //this is the jQuery function
//This is your code wrapped in a function called 'yourCode'
function yourCode() {
var $input = $('input:text'),
$apply = $('#apply');
$apply.attr('disabled', true);
$input.keyup(function () {
var trigger = false;
$input.each(function () {
if (!$(this).val()) {
trigger = true;
}
});
trigger ? $apply.attr('disabled', true) : $apply.removeAttr('disabled');
});
}
$(yourCode); //this is passing the jQuery function a function,
//this will now be execute once the page is loaded
//or what most people do, pass in as an anonymous function
//which eliminates a step
$(function () {
var $input = $('input:text'),
$apply = $('#apply');
$apply.attr('disabled', true);
$input.keyup(function () {
var trigger = false;
$input.each(function () {
if (!$(this).val()) {
trigger = true;
}
});
trigger ? $apply.attr('disabled', true) : $apply.removeAttr('disabled');
});
});
as suggested by #j08691 I would suggest reading about the document ready in jQuery here
I'm just getting started with Knockout.js and i have a view(html) which is supposed to be populated by data from a rest api via jquery's $.getJSON method.
When i run the app, nothing shows but using firebug i can see that the 'GET' query returns a status code of 200 and the right data.
I'm at a fix as to why nothing shows in the view since the bindings in Knockout.js are supposed to be automatic.
Below is my code.
Thanks
<div id ='main'>
<!-- ko foreach: posts -->
<p>Hello</p><span data-bind="text: title"></span></p><p data-bind="text: content"></p>
<p data-bind="text: author"></p><p data-bind="text: date"></p>
<!-- /ko -->
</div>
</body>
<script type="text/javascript">
function Post(data){
this.title = ko.observable(data.title);
this.content = ko.observable(data.content);
this.author = ko.observable(data.author);
this.date = ko.observable(data.date)
}
function PostListViewModel(){
var self = this;
self.posts = ko.observableArray([]);
$.getJSON("/posts", function(getPost){
var mappedPost = $.map(getPost, function(item){
return new Post(item)
});
self.posts(mappedPost);
});
}
var postlistviewmodel = new PostListViewModel();
ko.applyBindings(postlistviewmodel);
</script>
This should be:
$.getJSON("/posts", function(getPost){
var mappedPosts = $.map(getPost, function(item){
return new Post(item)
});
self.posts(mappedPosts);
});
wouldn't do self.posts.push(mappedPosts[i]) at all. You should just pass mappedPosts through the ko binding in order to update the listeners.
If your just getting the latest posts and want to update your current list simply do:
var allPosts = self.posts().concat(mappedPosts);
self.posts(allPosts);
You don't need the model to have ko.observable if you're just displaying them. If you want to edit model as well, then leave as.
Also, I tend to do this for single or multiple view models:
ko.applyBindings({viewModel : new viewModel() };
This allows for having multiple named view models. Access scope using: $root.viewModel
This is what I did earlier: http://jsfiddle.net/jFb3X/
Check your code against this fiddle then.
Script tags also need to be above the closing body tags
<html>
<head>
</head>
<body>
<!-- all your html content -->
<script type="text/javascript">
var viewModel = function () {
}
ko.applyBindings({viewModel : new viewModel()});
</script>
</body>
</html>
Is it something as simple as waiting for the DOM to be ready?
Are you able to try the following:
$(function () {
ko.applyBindings(postlistviewmodel);
});
Source: I've done this a few times and been stumped for a bit trying to see what I did wrong. :-)
(As a style thing, I'd also move the /body to after the /script - probably not related to your issue though).
I suspect you get multiple posts from /posts. You only push a single item (array).
...
$.getJSON("/posts", function(getPost){
var mappedPosts = $.map(getPost, function(item){
return new Post(item)
});
for(var i = 0; i < mappedPosts.length; i++) {
self.posts.push(mappedPosts[i]);
}
});
...
I have been trying to pass a value from an external javascript file to an HTML form with no luck. The files are rather large so I am not sure I can explain it all but ill try.
Basically a user clicks a link then a js file is initiated. Immediately after a new HTML page loads.
I need this value passed to the HTML page in a form field.
Javascript:
var divElement = function(){
divCode = document.getElementById(div1).innerHTML;
return divCode; };
document.getElementById('adcode').value = divElement();
Afterwards it should be passed to this Form field
HTML Form Field:
<p>Ad Code:<br>
<input type="text" name="adcode" id="adcode"/>
<br>
</p>
Thanks for any help!
Your HTML file needs to reference the JavaScript js file. Have a function in your JavaScript that returns the value that you need. Use JavaScript (I like jQuery) to set the form field to what you need.
JS file:
<script>
var divElement = function(){
divCode = document.getElementById(div1).innerHTML;
return divCode; };
document.getElementById('adcode').value = divElement();
function GetDivElement() {
return divElement();
}
</script>
HTML file:
<p>Ad Code:
<br />
<input type="text" name="adcode" id="adcode"/>
<br />
</p>
<script src="wherever that js file is" />
<script>
window.onload = function() {
document.getElementById('adcode').value = GetDivElement();
}
</script>
Although, really, this might do what you want (depending on what you are trying to do):
<p>Ad Code:
<br />
<input type="text" name="adcode" id="adcode"/>
<br />
</p>
<script src="wherever that js file is" />
<script>
window.onload = function() {
GetDivElement();
}
</script>
Can it be this?:
function divElement(divCode){
return divCode;
}
divElement(document.getElementById('adcode').value);
I have this knockout code:
function Task(data) {
this.title = ko.observable(data.title);
this.isDone = ko.observable(data.isDone);
}
function TaskListViewModel() {
// Data
var self = this;
self.tasks = ko.observableArray([]);
self.newTaskText = ko.observable();
self.incompleteTasks = ko.computed(function() {
return ko.utils.arrayFilter(self.tasks(), function(task) { return !task.isDone() });
});
// Operations
self.addTask = function() {
self.tasks.push(new Task({ title: this.newTaskText() }));
self.newTaskText("");
};
self.removeTask = function(task) { self.tasks.remove(task) };
}
ko.applyBindings(new TaskListViewModel());
This html:
<head>
<script type="text/javascript" src="jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="knockout-2.0.0.js"></script>
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<h3>Tasks</h3>
<form data-bind="submit: addTask">
Add task: <input data-bind="value: newTaskText" placeholder="What needs to be done?" />
<button type="submit">Add</button>
</form>
<ul data-bind="foreach: tasks, visible: tasks().length > 0">
<li>
<input type="checkbox" data-bind="checked: isDone" />
<input data-bind="value: title, disable: isDone" />
Delete
</li>
</ul>
You have <b data-bind="text: incompleteTasks().length"> </b> incomplete task(s)
<span data-bind="visible: incompleteTasks().length == 0"> - it's beer time!</span>
</body>
The example is the same as the one found on the Knockout website, but when I run it, it returns this message on Chrome Fire Bug:
Uncaught TypeError: Cannot read property 'nodeType' of null
This one is related to the knockout file and to this line of my script:
ko.applyBindings(new TaskListViewModel());
And this error is pointing to this line (1766) on knockout:
var isElement = (nodeVerified.nodeType == 1);
What am I doing wrong?
This problem was happening because I was trying to bind an HTML element before it was created.
My script was loaded on top of the HTML (in the head) but it needed to be loaded at the bottom of my HTML code (just before the closing body tag).
Thanks for your attention James Allardice.
A possible workaround is using defer="defer"
<script src="script.js" type="text/javascript" defer="defer"></script>
Use this if the script is not going to generate any document content. This will tell the browser that it can wait for the content to be loaded before loading the script.
Further reading.
Hope it helps.
You might want to consider using the jquery ready handler for this
$(function() {
function TaskListViewModel() {
...
ko.applyBindings(new TaskListViewModel());
});
Then you achieve two things:
Avoid polluting the global namespace
Knockout binding occurs AFTER the DOM is created. You can place your javascript wherever it is suited for organization.
See http://api.jquery.com/ready/
if you have jQuery put apply binding inside onload so that knockout looks for the DOM when DOM is ready.
$(document).ready(function(){
ko.applyBindings(new TaskListViewModel());
});
You have a simple spelling mistake:
self.addTask = fuction() {
Should be:
self.addTask = function() { //Notice the added 'n' in 'function'