I'm new on Knockout js.Trying to implement countdown timer on html with using knockout js
For this purpose I added 4 html elements(input, span and start, stop buttons) on view. When start button is pressed, the value that written on <input> objects should be passed to refreshViewModel, and there will be countdown process. When the countdown is processing remaining time will be showed inside <span> element. If the stop button is pressed countdown will be stopped.
If the countdown finishes another function(that is callbacked from another viewModel) which is filtering the page with some parameters will be initiated.
Binded textbox value to span value. I cannot figure out how to count and show to remaining value inside span dynamically?
Html:
<div id="pnlTimer" class="row">
<div class="span2 pull-right" style="border:1px solid rgb(218, 218, 218)" >
<span style="font-weight:bold">Reload Interval</span>
<br />
<input id="initialTime" style="width:20px;height:14px" data-bind="value: initialTime" />
<span id="remainingTime" style="visibility:hidden"> / 15</span> second(s)
<button class="btn" style="margin-top:5px" id="StartCounter" data-bind="click: StartCounter">
<i class="icon-play"></i>
</button>
<button style="visibility:hidden;margin-top:5px;margin-left:-44px" class="btn" id="StopCounter" data-bind="click: StopCounter">
<i class="icon-stop"></i>
</button>
</div>
</div>
Js:
#Url.Content("~/Content/App/viewModels/listCasesViewModel.js
#Url.Content("~/Content/App/viewModels/RefreshPageTimerViewModel.js
$(document).ready(function () {
var viewModel = new ListCasesViewModel();
viewModel.init();
var pnl = $("#pnlFilterPanel").get()[0];
ko.applyBindings(viewModel, pnl);
var viewModelTimer = new RefreshPageTimerViewModel();
viewModelTimer.init();
var pnlTimer = $("#pnlTimer").get()[0];
ko.applyBindings(viewModelTimer, pnlTimer);
viewModelTimer.callBackMethod = viewModel.filter;
});
First viewModel :RefreshPageTimerViewModel:
var RefreshPageTimerViewModel = function () {
var self = this;
self.StartCounter = ko.observable();
self.StopCounter = ko.observable();
self.initialTime = ko.observable();
self.remainingTime = ko.computed(function () {
return self.initialTime();
}, self);
countDown: ko.observable()
this.init = function () {
self.Count();
}
this.callBackMethod = function () {
alert("not implemented!");
}
this.Count = function () {
var initial = self.initialTime; // initialTime value;
var remaining = self.remainingTime;
if (remainingTime <= 0) {
this.ExecuteCallBackMethod();
}
}
this.ExecuteCallBackMethod = function () {
this.callBackMethod();
}
};
Second viewModel: ListCasesViewModel:
var ListCasesViewModel = function () {
var self = this;
self.selectedStartDate = ko.observable(null);
self.selectedEndDate = ko.observable(new Date());
self.selectedSearchKey = ko.observable("");
self.selectedStatuses = ko.observableArray();
self.selectedHospitals = ko.observableArray();
// methods...
this.init = function () {
self.selectedEndDate(new Date());
self.filter();
}
this.filter = function () {
// get filter control values
var startDate = self.selectedStartDate(); // dtStart.value();
var endDate = self.selectedEndDate(); //dtEnd.value();
var searchText = self.selectedSearchKey();
//And Some calculations....
The main problem is your ViewModel code, it uses an observable where you wanted a function (to Start and Stop the counter). Also, it does not seem to have a clear definition of what it is trying to do.
Also, im assuming you wanted the Start button to show when the timer is stopped, and the Stop button to show when the timer is started - so ive taken the liberty to add this functionality too.
Here is the rewritten view model:
var RefreshPageTimerViewModel = function () {
var self = this;
self.timerId = 0;
self.elapsedTime = ko.observable(0);
self.initialTime = ko.observable(0);
self.remainingTime = ko.computed(function(){
return self.initialTime() - self.elapsedTime();
});
self.isRunning = ko.observable(false);
self.StartCounter = function(){
self.elapsedTime(0);
self.isRunning(true);
self.timerId = window.setInterval(function(){
self.elapsedTime(self.elapsedTime()+1);
if(self.remainingTime() == 0){
clearInterval(self.timerId);
self.isRunning(false);
self.Callback();
}
},1000)
}
self.StopCounter = function(){
clearInterval(self.timerId);
self.isRunning(false);
}
self.Callback = function(){}
}
A few things to note:
Has a property timerId, which does not need to be observable, but allows us to stop the timer which is used to increment the elapsedTime
has an observable property isRunning used to control the visibility of the Start and Stop buttons
has an empty function Callback which can be used to execute any function when the countdown reaches zero.
Here is the new markup:
<div id="pnlTimer" class="row">
<div class="span2 pull-right" style="border:1px solid rgb(218, 218, 218)" >
<span style="font-weight:bold">Reload Interval</span>
<br />
<input id="initialTime" style="width:20px;height:14px" data-bind="value: initialTime" />
<span id="remainingTime" data-bind="text: remainingTime"></span> second(s)
<button class="btn" style="margin-top:5px" id="StartCounter" data-bind="click: StartCounter, visible: !isRunning()">
start
</button>
<button style="margin-top:5px" class="btn" id="StopCounter" data-bind="click: StopCounter, visible:isRunning()">
Stop
</button>
</div>
</div>
Note the addition of visible: !isRunning() to the start and visible:isRunning() to the stop buttons.
Finally, here is the init code:
$(function(){
var viewModelTimer = new RefreshPageTimerViewModel();
viewModelTimer.Callback = function(){
alert("finished");
};
ko.applyBindings(viewModelTimer);
})
Note the creation of a callback function which simply alerts. Your code could be as it was, ie viewModelTimer.callBackMethod = viewModel.filter;
Finally, a live example to allow you to play around: http://jsfiddle.net/eF5Ec/
Related
This code successfully takes the contents of the form and saves it to an ordered list, 2 more functions do the same thing but instead create a timestamp. I'm trying to take every li element that gets generated and save it to localStorage when you push the save button and then repopulate it again from the local storage when you push the "load" button. I can't get it to work come hell or high water. The load button does nothing, and oddly enough the "save" button acts as a clear all and actually removes everything rather then saving it. Console log shows no errors. I have the JavaScript below and the corresponding HTML.
let item;
let text;
let newItem;
function todoList() {
item = document.getElementById("todoInput").value
text = document.createTextNode(item)
newItem = document.createElement("li")
newItem.onclick = function() {
this.parentNode.removeChild(this);
}
newItem.onmousemove = function() {
this.style.backgroundColor = "orange";
}
newItem.onmouseout = function() {
this.style.backgroundColor = "lightblue";
}
todoInput.onclick = function() {
this.value = ""
}
newItem.appendChild(text)
document.getElementById("todoList").appendChild(newItem)
};
function save() {
const fieldvalue = querySelectorAll('li').value;
localStorage.setItem('item', JSON.stringify(item));
}
function load() {
const storedvalue = JSON.parse(localStorage.getItem(item));
if (storedvalue) {
document.querySelectorAll('li').value = storedvalue;
}
}
<form id="todoForm">
<input id="todoInput" value="" size="15" placeholder="enter task here">
<button id="button" type="button" onClick="todoList()">Add task</button>
<button id="save" onclick="save()">Save</button>
<button id="load" onclick="load()">Load</button>
</form>
As #Phil and #Gary explained part of your problem is trying to use querySelectorAll('li') as if it would return a single value. You have to cycle through the array it returns.
Check the below code to give yourself a starting point. I had to rename some of your functions since they were causing me some errors.
<form id="todoForm">
<input id="todoInput" value="" size="15" placeholder="enter task here">
<button id="button" type="button" onClick="todoList()">Add task</button>
<button id="save" onclick="saveAll()" type="button">Save</button>
<button id="load" onclick="loadAll()" type="button">Load</button>
</form>
<div id="todoList"></div>
<script>
let item;
let text;
let newItem;
function todoList() {
item = document.getElementById("todoInput").value
text = document.createTextNode(item)
newItem = document.createElement("li")
newItem.onclick = function() {
this.parentNode.removeChild(this);
}
newItem.onmousemove = function() {
this.style.backgroundColor = "orange";
}
newItem.onmouseout = function() {
this.style.backgroundColor = "lightblue";
}
todoInput.onclick = function() {
this.value = ""
}
newItem.appendChild(text)
//Had to add the element
document.getElementById("todoList").appendChild(newItem);
}
function saveAll() {
//Create an array to store the li values
var toStorage = [];
var values = document.querySelectorAll('li');
//Cycle through the li array
for (var i = 0; i < values.length; i++) {
toStorage.push(values[i].innerHTML);
}
console.log(toStorage);
//CanĀ“t test this on stackoverflow se the jsFiddle link
localStorage.setItem('items', JSON.stringify(toStorage));
console.log(localStorage);
}
function loadAll() {
const storedvalue = JSON.parse(localStorage.getItem('items'));
console.log(storedvalue);
//Load your list here
}
</script>
Check https://jsfiddle.net/nbe18k2u/ to see it working
HTML
<div id = "btnsdhd" class="btn-group">
<button type="button" id="31" value="SD" class="btn btn-default">SD</button>
<button type="button" id="32" value="HD" class="btn btn-default">HD</button>
</div>
JS
var btnsdhdDiv = $('#btnsdhd');
var getsdhd = function () {
// Get all sdhd's from buttons with .active class
var sdhd = $('button.active', btnsdhdDiv).map(function () {
return $(this).val();
}).get();
// If no sdhd's found, get sdhd's from any button.
if (!sdhd || sdhd.length <= 0) {
sdhd = $('button', btnsdhdDiv).map(function () {
return $(this).val();
}).get();
}
return sdhd;
};
The above code captures the values of the buttons and places it in the variable getsdhd
If none of the buttons are selected by default it captures both the values (SD,HD) I want to modify the if statement and add a third value NC to the variable when to no buttons are selected
I want it to look like (SD,HD,NC) when no buttons are slected.
I tried to use the .push() method but that didnt work.
Any leads would be helpful.
push() can not be chained in your case since push returns the new length, not the updated array. You need to add it below the get().
var btnsdhdDiv = $('#btnsdhd');
var getsdhd = function () {
// Get all sdhd's from buttons with .active class
var sdhd = $('button.active', btnsdhdDiv).map(function () {
return $(this).val();
}).get();
// If no sdhd's found, get sdhd's from any button.
if (!sdhd || sdhd.length <= 0) {
sdhd = $('button', btnsdhdDiv).map(function () {
return $(this).val();
}).get()
sdhd.push("NC");
}
return sdhd;
};
console.log(getsdhd());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id = "btnsdhd" class="btn-group">
<button type="button" id="31" value="SD" class="btn btn-default">SD</button>
<button type="button" id="32" value="HD" class="btn btn-default">HD</button>
</div>
You are not invoking the getsdhs function. If you invoke your function it will work. I used console.log to test if it works.
JS
var btnsdhdDiv = $('#btnsdhd');
var getsdhd = function () {
// Get all sdhd's from buttons with .active class
var sdhd = $('button.active', btnsdhdDiv).map(function () {
return $(this).val();
}).get();
// If no sdhd's found, get sdhd's from any button.
if (!sdhd || sdhd.length <= 0) {
sdhd = $('button', btnsdhdDiv).map(function () {
return $(this).val();
}).get();
sdhd.push("NC");
}
console.log(sdhd);
return sdhd;
}();
Fiddle: https://jsfiddle.net/ABr/p23cb5dk/1/
I have a simple html page with value input and save button.
I want the save will be enabled only if the value is changed (somtimes is initialized and somtimes not.
I've tryied few things without any success
HTML
<input type="text"
placeholder="type here"
data-bind="value: rate,"/>
<button data-bind="click: save">Save</button>
JS
var viewmodel = function () {
this.rate = ko.observable('88').extend(required: true);
};
viewmodel.prototype.save = function () {
alert('save should be possible only if rate is changed);
};
Also on jsfiddle
Should be able to achieve this with a computed observable and the enable binding.
See http://jsfiddle.net/brendonparker/xhLrB/1/
Javascript:
var ctor = function () {
var self = this;
self.originalRate = '88';
self.rate = ko.observable('');
self.canSave = ko.computed(function(){
return self.originalRate == self.rate();
});
};
ctor.prototype.save = function () {
alert('save should be possible only if rate is changed');
};
ko.applyBindings(new ctor());
HTML:
<input type="text" placeholder="type here" data-bind="value: rate, valueUpdate: 'afterkeydown'"/>
<button data-bind="click: save, enable: canSave">Save</button>
Here's a demo of what I'm talking about - http://jsfiddle.net/MatthewKosloski/qLpT9/
I want to execute code if "Foo" has been clicked, and a number has been entered in the input.. and if "send" has been clicked.
<h1>Foo</h1>
<input type="text" id="amount" placeholder="Enter in a number."/>
<button id="send">Send</button>
I'm pretty sure I'm overthinking this, I'd appreciate the help on such a concise question.
try this one: jfiddle link
var send = document.getElementById("send");
var h1 = document.getElementsByTagName("h1");
var foo_clicked = 0;
h1[0].onclick = function(){foo_clicked += 1; };
send.onclick = function(){
if(document.getElementById("amount").value !='' && foo_clicked >0 )
alert ('poor rating');
};
As per your statement & taking some assumptions, try this way:
(This executes function twice - When there is a change of text or a click of the button).
HTML:
<h1 id="">Foo</h1>
<input type="text" id="amount" placeholder="Enter in a number."/>
<button id="sendBtn">send</button>
JS:
document.getElementById("amount").addEventListener("change",poorRatingCalculation);
document.getElementById("sendBtn").addEventListener("click",poorRatingCalculation);
function poorRatingCalculation() {
var rating = document.getElementById("amount").value;
if(rating=="poor") alert("Poor Service");
}
DEMO: http://jsfiddle.net/wTqEv/
A better, self contained example:
http://jsfiddle.net/qLpT9/7/
(function()
{
var clicked = false;
var header = document.getElementById("header");
var amount = document.getElementById("amount");
var send = document.getElementById("send");
header.addEventListener("click", function()
{
clicked = true;
});
send.addEventListener("click", function()
{
if(!clicked)
{
return
}
// Foo has been clicked
var value = amount.value;
console.log(value;)
});
})();
Is this what you were looking for?
http://jsfiddle.net/qLpT9/5/
function poorRatingCalculation(){
if(myInput.value) {
alert(myInput.value);
}
}
var foo = document.getElementById("foo"),
myInput = document.getElementById("amount");
foo.addEventListener("click", poorRatingCalculation, false)
Looking for a good example of how to set up child models in knockoutjs. This includes binding to child events such as property updates which I haven't been able to get working yet.
Also, it would be better to bind to a single child in this case instead of an array but I don't know how to set it up in the html without the foreach template.
http://jsfiddle.net/mathewvance/mfYNq/
Thanks.
<div class="editor-row">
<label>Price</label>
<input name="Price" data-bind="value: price"/>
</div>
<div class="editor-row">
<label>Child</label>
<div data-bind="foreach: childObjects">
<div><input type="checkbox" data-bind="checked: yearRound" /> Year Round</div>
<div><input type="checkbox" data-bind="checked: fromNow" /> From Now</div>
<div>
<input data-bind="value: startDate" class="date-picker"/> to
<input data-bind="value: endDate" class="date-picker"/>
</div>
</div>
</div>
var ChildModel= function (yearRound, fromNow, startDate, endDate) {
var self = this;
this.yearRound = ko.observable(yearRound);
this.fromNow = ko.observable(fromNow);
this.startDate = ko.observable(startDate);
this.endDate = ko.observable(endDate);
this.yearRound.subscribe = function (val) {
alert('message from child model property subscribe\n\nwhy does this only happen once?');
//if(val){
// self.startDate('undefined');
// self.endDate('undefined');
//}
};
}
var ParentModel = function () {
var self = this;
this.price = ko.observable(1.99);
this.childObjects = ko.observableArray([ new ChildModel(true, false) ]);
};
var viewModel = new ParentModel ();
ko.applyBindings(viewModel);
Try it with the following:
this.yearRound.subscribe(function (val) {
alert('value change');
});
If you want to have the subscriber also being called while loading the page do something like this:
var ChildModel= function (yearRound, fromNow, startDate, endDate) {
var self = this;
this.yearRound = ko.observable();
this.fromNow = ko.observable(fromNow);
this.startDate = ko.observable(startDate);
this.endDate = ko.observable(endDate);
this.yearRound.subscribe(function (val) {
alert('value change');
});
this.yearRound(yearRound);
}
http://jsfiddle.net/azQxx/1/ - this works for me with Chrome 16 and Firefox 10
Every time the checked button changes its value the callback fires.
The observableArray is fine in my opinion if you may have more than one child model associated to the parent.