Knockout Input ReadOnly State - javascript

I am trying to add a simple functionality in my program and Im having a little trouble figuring out how to do something I wanted.
Here's what I got:
My input textbox, with a link beside it to disable/enable readonly property on that input textbox.
<div>
<input type="text" data-bind="attr: { 'readonly': getreadonlyState() }" value="420" />
Edit
</div>
Here's my knockout script for it:
var ViewModel = function() {
var self = this;
self.getreadonlyState = ko.observable('readonly');
self.readonly = function() {
if (self.getreadonlyState()) {
self.getreadonlyState(undefined);
}
else self.getreadonlyState('readonly');
}
}
ko.applyBindings(new ViewModel());
This works great, but what I wanted is when I click the edit link, it will change the text of the link to something like: "Stop Editing" so when I click "Stop Editing" the readonly property is enabled again.
Here's a fiddle of what Im working on.
Any help will be greatly appreciated, thank you!

Here's an alternative to #thangcao's answer. I'm not saying this is any better or worse, simply an alternative which uses a subscribe handler instead of a computedObservable.
<div>
<input type="text" data-bind="attr: { 'readonly': getreadonlyState() }" value="420" />
</div>
var ViewModel = function() {
var self = this;
self.getreadonlyState = ko.observable('readonly');
self.getreadonlyState.subscribe(function(val) {
self.linkText(val === "readonly" ? "Edit" : "Stop editing");
});
self.readonly = function() {
if (self.getreadonlyState()) {
self.getreadonlyState(undefined);
}
else self.getreadonlyState('readonly');
}
self.linkText = ko.observable("Edit");
}
ko.applyBindings(new ViewModel());
Notice that there's no need for the additional <span> in #thangcao's answer.
Also, why is the "edit"/"stop editing" element an anchor tag? Why not just make it a <span> and do away with the need for the additional inline JavaScript (which you can anyway replace with a return false; inside the readonly function).
http://jsfiddle.net/ajameson/eeTjS/87/

I have updated your Fiddle and hope that it meets your need:
<div>
<input type="text" data-bind="attr: { 'readonly': getreadonlyState() }" value="420" />
<span data-bind="text:linkText"></span>
</div>
var ViewModel = function() {
var self = this;
self.getreadonlyState = ko.observable('readonly');
self.readonly = function() {
if (self.getreadonlyState()) {
self.getreadonlyState(undefined);
}
else {
self.getreadonlyState('readonly');
}
}
self.linkText = ko.computed(function(){
return self.getreadonlyState() == 'readonly' ? "Stopping edit" : "Edit";
}, self);
}
ko.applyBindings(new ViewModel());

You can use this binginHandlers :
ko.bindingHandlers.readOnly = {
update: function (element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
if (value) {
element.setAttribute("disabled", true);
} else {
element.removeAttribute("disabled");
}
}
};
In my html :
<input type="text" id="create-finess" class="form-control" data-bind="readOnly: _locked" />
Finaly in my JS :
//Constructor of my view model
function ViewModel(resx) {
this._locked = ko.observable();
}
// on init of the page i lock the input
this._load = function () {
this._locked(true);
}

Related

Make invalid form immediately after loading

I have a simple form written in AngularJS.
I would like to make the form invalid immediately after loading. Unfortunately $scope.myForm.$valid = false; doesn't want work. Do you have any other technique to do it? It is important for me as I want to let user click the button only when he/she choose at least on checkbox. Now you can submit the form always after loading the form.
<form name="myForm" ng-submit="myForm.$valid">
<input type="checkbox" ng-model="obj.first" ng-change="onChange()" /> First <br />
<input type="checkbox" ng-model="obj.second" ng-change="onChange()"/>Second <br />
<input type="checkbox" ng-model="obj.third" ng-change="onChange()"/> Third <br>
<button type="submit" ng-disabled="!myForm.$valid" ng-click="click()">test</button> <br>
</form>
$scope.myForm = {};
$scope.myForm.$valid = false;
$scope.click=function () {
console.log('-------------2', $scope.myForm);
};
$scope.onChange=function () {
console.log('before:', $scope.myForm);
var isValid = false;
angular.forEach($scope.obj, function(value, key) {
if(value == true){
isValid=true;
}
console.log(key + ': ' + value);
});
if(!isValid){
$scope.myForm.$valid = false;
$scope.myForm.$error.checkBoxes = {
isChecked: false
};
}
console.log('after:', $scope.myForm);
}
So this is my final solution, the form in the scope has a function called $setValidity() where we can change the validity state, and notify the form. Refer here, so I check if any of the checkboxes are having true value, then I set the value for one checkbox alone as true, if not then one of the checkboxes with name one is set to $valid = false, thus the entire form will be invalid, please go through my code for the implementation of the solution!
JSFiddle Demo
JS:
var app = angular.module('myApp', []);
app.controller('MyController', function MyController($scope) {
$scope.onChange = function() {
if ($scope.obj) {
if ($scope.obj.first || $scope.obj.second || $scope.obj.third) {
$scope.myForm.one.$setValidity("Atleast one checkbox needs to be selected", true);
} else {
$scope.myForm.one.$setValidity("Atleast one checkbox needs to be selected", false);
}
} else {
$scope.myForm.one.$setValidity("Atleast one checkbox needs to be selected", false);
}
}
});
Try this in your submit button. hope it works
data-ng-disabled="myForm.$submitted || myForm.$invalid && !myForm.$pristine"

How to change CSS in Controller

I m trying to do a workaround for a bug. i need to just change the css of an element when an other checkbox is clicked. But it is not working.. It just works when i click on an other button somewhere else but when i click on the checkbox the view is not being refreshed maybe ?
Any ideas ?
View:
<input
type="checkbox"
value="application.callback" id="telefonBox"
ng-click="application.callback = !application.callback; toggleClass(application.callback)"
/>
Controller:
$scope.toggleClass = function(newValue) {
var element = angular.element(document.querySelector('#additional'));
if (newValue) {
element.toggleClass("tooltip-agent tooltip-agentChecked ");
} else {
element.toggleClass("tooltip-agentChecked tooltip-agent");
}
$scope.$apply();
}
i tried this to but not working
$scope.$watch('$scope.application.callback', function (newValue, oldValue) {
var element = angular.element(document.querySelector('#additional'));
if (newValue) {
element.toggleClass("tooltip-agent tooltip-agentChecked ");
} else {
element.toggleClass("tooltip-agentChecked tooltip-agent ");
}
add ng-modal into checkbox
<input type="checkbox" ng-model="application.callback">
and ng-class into your #additional element
<div id="additional" ng-class="{true:'tooltip-agent tooltip-agentChecked', false:'tooltip-agentChecked tooltip-agent'}[application.callback]"></div>
DEMO
You should not manipulate elements in angular as much as possible, you can do it easier with ng-class like this
<div id="test" ng-class='{ active: vm.isChecked }'>
lorem
</div>
ng-class accepts an object as parameter, in this case it's { active: vm.isChecked } which mean if vm.isChecked evaluates to true, the active class will be applied to the element
$scope.selection = function($event) {
var checkbox = $event.target;
var action = (checkbox.checked ? 'check' : 'uncheck');
if(action == "check")
angular.element(document.querySelector('#additional')).addClass("tooltip-agent tooltip-agentChecked");
else
angular.element(document.querySelector('#additional')).addClass("tooltip-agentChecked tooltip-agen");
};
});
<input type="checkbox" id="additional" ng-model="check" ng-click="selection($event)" >

Knockout.js enable save only if value change

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>

knockoutjs when checked data binding call function

I need to do following things: When user checks the checkbox, some function is called.
<input type="checkbox" data-bind="what to write here?" />
and in model:
var viewModel = {
this.someFunction = function() {
console.log("1");
}
};
I have not found anything about this is documentation here.
What you need is the click binding:
<input type="checkbox" data-bind="click: someFunction" />
And in your view model:
var ViewModel = function(data, event) {
this.someFunction = function() {
console.log(event.target.checked); // log out the current state
console.log("1");
return true; // to trigger the browser default behavior
}
};
Demo JSFiddle.
Or if you want to you use the checked binding you can subscribe on the change event of your property:
<input type="checkbox" data-bind="checked: isChecked" />
And in your viewmodel:
var ViewModel = function() {
this.isChecked = ko.observable();
this.isChecked.subscribe(function(newValue){
this.someFunction(newValue);
}, this);
this.someFunction = function(value) {
console.log(value); // log out the current state
console.log("1");
}
};
Demo JSFiddle.

how to write onblur and onfocus event in javascript?

Question:
<body onload="setBlurFocus()">
<form method="POST" action="#">
<input id="id_username" type="text" name="username" maxlength="100" />
<input type="text" name="email" id="id_email" />
<input type="password" name="password" id="id_password" />
</form>
</body>
I wrote :
function setBlurFocus () {
var user_input = document.getElementById('id_username');
var email = document.getElementById('id_email');
var password = document.getElementById('id_password');
user_input.onblur = userSetBlur();
email.onblur = emailSetBlur();
password.onblur = passSetBlur();
user_input.onfocus = function() {
document.getElementById('id_username').value = ''
}
email.onfocus = function() {
document.getElementById('id_email').value = ''
}
password.onfocus = function() {
document.getElementById('id_password').value = ''
}
}
function userSetBlur() {
document.getElementById('id_username').value = 'Username'
}
function emailSetBlur() {
document.getElementById('id_email').value = 'Email'
}
function passSetBlur() {
document.getElementById('id_password').value = 'Password'
}
Question?
How to generalize or optimized this code?
You can always attach the methods in JavaScript:
function setBlurFocus() {
var user_input = document.getElementById('id_username');
user_input.onblur = someFunction;
// or with an anonymous function:
user_input.onfocus = function() {
// do something
}
}
Read more about traditional event handling and events in general.
Further explanation:
You attached the function setBlurFocus to the load event of the document. This is correct if you have to access DOM elements with JavaScript. The load event is fired when all the elements are created.
If you attach the setBlurFocus() to the blur event of the input field, then the function is only executed when the text box looses focus.
From your question I concluded you don't want set the event handlers in the HTML, but you want to set them form inside the setBlurFocus function.
Regarding your update:
This is wrong:
user_input.onblur = userSetBlur();
This assigns the return value of the function to onblur. You want to assign the function itself, so you have to write:
user_input.onblur = userSetBlur;
The () calls the function. You don't want that (in most cases, there are exceptions, see below).
Furthermore, you don't have to use named functions for onblur and anonymous functions for onfocus. It was just an example, to show you the different possibilities you have. E.g. if you assign an event handler to only one element, then there is no need to define it as extra function. But you have to do this if you want to reuse event handlers.
Here is an improved version:
function setBlurFocus () {
var values = ["Username", "Email", "Password"];
var elements = [
document.getElementById('id_username'),
document.getElementById('id_email'),
document.getElementById('id_password')
];
for(var i = elements.length; i--; ) {
elements[i].onblur = setValue(values[i]);
elements[i].onfocus = emptyValue;
}
}
function setValue(defaultValue) {
return function(){this.value = defaultValue;};
}
function emptyValue() {
this.value = '';
}
this inside the event handlers refers to the element the handler is bound to.
Note: Here setValue returns a function, that is why we call setValue in this case (and not just assign it).
Important note: This will also reset the values to Username etc, if the user entered some data. You have to make sure, that you only reset it if the user has not entered data. Something like:
function setValue(defaultValue) {
return function(){
if(this.value !== "") {
this.value = defaultValue;
}
};
}
and you'd have to define emptyValue similar:
function emptyValue(defaultValue) {
return function(){
if(this.value === defaultValue) {
this.value = "";
}
};
}
Now that I know what you actually want to do, have also a look at HTML5's placeholder attribute.
Well you've tagged it with jquery so this is how to do it in jquery:
function setBlurFocus () {
//do stuff here
}
$('#id_username').blur(setBlurFocus);
or
$('#id_username').blur(function(){
//do stuff here
});
Regarding your update
I using jquery as you tab jquery, the code was bellow , you can check a live sample with this link :
http://jsfiddle.net/e3test/zcGgz/
html code :
<form method="POST" action="#">
<input id="id_username" type="text" name="username" maxlength="100" />
<input type="text" name="email" id="id_email" />
<input type="password" name="password" id="id_password" />
</form>
javascript code :
$(function(){
var selector = {
username: $('#id_username'),
email: $('#id_email'),
password: $('#id_password')
};
for (var x in selector) {
selector[x].focus(function(){
$(this).val('');
}).blur(function(){
$(this).val($(this).attr('name'));
});
}
});
Hope it help.

Categories