I have a table like below:
<tbody data-bind="foreach: tasks">
<tr>
<td>
<span data-bind="text: goal" />
</td>
<td>
<input type="text" data-bind="value: note ,
disable: !($data.isAllowedForMember)" />
</td>
</tr>
</tbody>
I want to make note textbox disable when isAllowedForMember = false. But everytime its making note disable(wheather isAllowedForMember = true or false).
Here is my viewmodel
//viewmodel
function GoalSheetViewModel() {
self.tasks = ko.observableArray([]); //tasklist
self.note = ko.observable();
self.isAllowedForMember = ko.observable();
self.IsAllowedToChange = function () {
$.ajax({
success: function (results) {
self.isAllowedForMember(results.d);
},
})
};
};
You should unwrap observable if you use it in condition:
<input type="text" data-bind="value: note , disable: !$parent.isAllowedForMember()" />
The following article can help you to learn some useful things about knockout: http://www.knockmeout.net/2011/06/10-things-to-know-about-knockoutjs-on.html
EDIT:
isAllowedForMember is member of parent context so you should use $parent object to access it:
<input type="text" data-bind="value: note , disable: !$parent.isAllowedForMember()" />
As Artem said you need to unwrap the observable, but even better to use a computed with a name saying what the business rule means
like
this.readonlyMember = ko.computed(function() {
return this.isAllowedForMember();
}, this);
But you also have a releation problem with your model since you get
ReferenceError: isAllowedForMember is not defined
Related
I have a table in which one item is editable. On clicking that item, the text changes to a text box and it can be edited. The issue is, on clicking the text, the text changes to textbox but I'm not able to focus on the textbox.
This is the code
JS
$scope.togglePrice = function (item) {
item.showUpdatePrice = true;
}
HTML
<a ng-click="togglePrice(item)" ng-hide="item.showUpdatePrice" style="text-decoration:underline; cursor:pointer;">{{item.sellingPrice | currencyFormat}}</a>
<input id="updatePriceId" ng-model="item.sellingPrice" class="form-control" ng-class="{'errorClass': showPriceError}" ng-show="item.showUpdatePrice" ng-blur="saveUpdatedPrice(item)" type="text" placeholder="Enter Price">
Edit
<tbody ng-repeat="item in shoppingItems">
<tr>
<td class="priceDiv">
<div>
<a ng-click="togglePrice(item)" ng-hide="item.showUpdatePrice" style="text-decoration:underline; cursor:pointer;">{{item.sellingPrice | currencyFormat}}</a>
<input ng-model="item.sellingPrice" auto-focus class="form-control" ng-class="{'errorClass': showPriceError}" ng-show="item.showUpdatePrice" ng-blur="saveUpdatedPrice(item)" type="text" placeholder="Enter Price">
</div>
</td>
</tr>
</tbody>
You should make a small change to your method and should add one directive to achieve your solution.
$scope.togglePrice = function (item) {
item.showUpdatePrice = !item.showUpdatePrice;
}
In this solution, on click on the text-boxes, the respective textbox gets focussed, and on blur or clicking outside, it gets unfocussed.
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body ng-app="myApp">
Click to focus on Below TextBoxes:
<table ng-controller="myCtrl">
<tbody ng-repeat="item in shoppingItems">
<tr>
<td class="priceDiv">
<div>
<a ng-click="togglePrice(item)" ng-hide="item.showUpdatePrice" style="text-decoration:underline; cursor:pointer;">{{item.sellingPrice}}</a>
<input ng-model="item.sellingPrice" auto-focus class="form-control" ng-class="{'errorClass': showPriceError}" ng-show="item.showUpdatePrice" ng-blur="saveUpdatedPrice(item)" type="text" placeholder="Enter Price" focus-me="item.showUpdatePrice">
</div>
</td>
</tr>
</tbody>
</table>
<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.togglePrice = function (item) {
item.showUpdatePrice = !item.showUpdatePrice;
}
$scope.shoppingItems = [
{
"showUpdatePrice" : false,
"sellingPrice" : "10"
},
{
"showUpdatePrice" : false,
"sellingPrice" : "20"
},
{
"showUpdatePrice" : false,
"sellingPrice" : "30"
},
]
});
app.directive('focusMe', ['$timeout', '$parse', function ($timeout, $parse) {
return {
link: function (scope, element, attrs) {
var model = $parse(attrs.focusMe);
scope.$watch(model, function (value) {
if (value === true) {
$timeout(function () {
element[0].focus();
});
}
});
element.bind('blur', function () {
scope.$apply(model.assign(scope, false));
});
}
};
}]);
</script>
</body>
</html>
PLEASE RUN THE ABOVE SNIPPET
Here is a working DEMO
Update your code with below code, may be it helps you. It will add a unique id to your inputs according to index. So you can simply access them using most efficient javascript selector.
Change your javascript to
$scope.togglePrice = function (item, buttonClicked) {
item.showUpdatePrice = true;
setTimeout(function(){
document.getElementById(buttonClicked).focus();
});
}
And in html
<tbody ng-repeat="item in shoppingItems">
<tr>
<td class="priceDiv">
<div>
<a ng-click="togglePrice(item, $index)" ng-hide="item.showUpdatePrice" style="text-decoration:underline; cursor:pointer;">{{item.sellingPrice | currencyFormat}}</a>
<input id='{{$index}}' ng-model="item.sellingPrice" auto-focus class="form-control" ng-class="{'errorClass': showPriceError}" ng-show="item.showUpdatePrice" ng-blur="saveUpdatedPrice(item)" type="text" placeholder="Enter Price">
</div>
</td>
</tr>
</tbody>
Try this May be it helps you. Thanks
I want to make a search on the column SN in a table.
there many information in my table, I want to be able to search based on SN but when I add the filter it does not even load my table
This is what I did:
in My controler my List is filled :
$scope.List = {};
MyServices.getList()
.success(function (data) {
angular.forEach(data, function (value, index) {
$scope.List[value.SN] = {
Description: value.Description,
SN: value.SN
}
});
})
.error(function (error) {
$scope.status = 'Unable to load customer data: ' + error.message;
});
and this is my HTML:
<label>Search: <input ng-model="search.SN"></label>
<tr ng-repeat="V in List| filter:search">
<td>{{V.SN}}</td>
<td>{{V.Description}}</td>
</tr>
You must write as follow:
<label>Search: <input ng-model="search.SN"></label>
<tr ng-repeat="V in List| filter: {SN: search.SN}">
<td>{{V.SN}}</td>
<td>{{V.Description}}</td>
</tr>
Remove the object declaration on the input field. It will match the whole object for your specified value on the input field:
<label>Search: <input ng-model="search"></label>
<tr ng-repeat="V in List| filter: search">
<td>{{V.SN}}</td>
<td>{{V.Description}}</td>
</tr>
We are in the process of converting a very old ColdFusion application that made convenient use of "this" in conjunction with a function that did formatting:
<td>$<input type="text" name="txtTaxProration" id="txtTaxProration" value="0.00" alt="Tax Proration" onblur="dollarBlur(this);"></td>
The dollarBlur function would convert the numeric input to currency, i.e if the user entered 123, it was converted to 123.00; 23.45 was left as 23.45. This made the reference on the HTML side easy, but even easier in the actual function as the name of the element did not have to be specified. Is there some analogous way to do this in Angular?
<td>$<input type="text" ng-model="NetSheetDetail.TxtHomeWarranty" name="txtHomeWarrantyPolicy" id="txtHomeWarrantyPolicy" value="0.00" ng-change="angularDollarBlur(this)" ng-model-options="{ updateOn: 'blur' }"></td>
The following works fine, almost, HTML
<input type="text" ng-model="NetSheetDetail.TxtHomeWarranty" ng-change="reCalcX('NetSheetDetail.TxtHomeWarranty')" ng-model-options="{ updateOn: 'blur' }" ></td>
Controller
$scope.reCalcX = function (propName) {
alert($scope.$eval(propName));
$scope['propName'] = 666;
};
$scope.$eval(propName) does correctly reflect what was entered on the webpage ($scope['propName'] is undefined). However, $scope['propName'] doesn't appear to work - the change is not reflected back in the webpage.
Yes, simply pass the model.
ng-change="angularDollarBlur(NetSheetDetail.TxtHomeWarranty)"
$scope.angularDollarBlur = function (model) {
console.log(model);
}
Here's another example:
angular.module('app',[]).controller('myController', function ($scope) {
$scope.NetSheetDetail = {
TxtHomeWarranty: 'Hello World!'
};
$scope.angularDollarBlur = function (text, obj, prop) {
alert(text);
obj[prop] = 'Nope.';
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="myController">
<input type="text" ng-model="NetSheetDetail.TxtHomeWarranty" ng-change="angularDollarBlur(NetSheetDetail.TxtHomeWarranty,NetSheetDetail,'TxtHomeWarranty')" />
</div>
Below is my html:
<tr ng-repeat="c in client">
<td><input type =text id = "id" value = {{c.id}} onclick = "display();" > </input> </td>
<td><input type =text value = {{c.fname}}></td>
</tr>
My js:
function display()
{
var x=document.forms["form"]["id"].value;
alert(x);
}
I am getting the input value in the alert box successfully but how to get this value in another angular js function. I tried the below code but not working please suggest me
<input type =text id = "id" value = {{c.id}} ng-model = user.id ng-click ="init(user)" > </input>
If you have set up your application properly, you simply create the init() function in your controller
$scope.init = function (user) {
// function implementation
};
Also make sure you format your HTML correctly
<input type="text" id="id" value="{{c.id}}" ng-model="user" ng-click ="init(user)" />
A much more cleaner way to accomplish the same thing would be to just set the value on the click event for example.
<td onclick="user.id=ID"> </td>
I'm having data binding a knockout function to my html.
Following is the view model:
var DonutViewModel = function () {
this.donuts = ko.observableArray();
//donutData = JSON.parse(donutData);
var items = $.map(donutData, function (data) { return new Donut(data) });
this.donuts(items);
this.deletedonut = function (item) {
this.donuts.remove(item);
}
}
var viewModel;
$(document).ready(function () {
viewModel = new DonutViewModel();
ko.applyBindings(viewModel);
});
following is the html:
<tr>
<td><input id="txtdonutid" type="text" data-bind="value:id"/></td>
<td><input id="txtdonuttype" type="text" data-bind="value:type"/></td>
<td><input id="txtdonutname" type="text" data-bind="value:dname"/></td>
<td><input id="txtppu" type="text" data-bind="value:ppu"/></td>
<td><input type="button" value="Delete Donut" data-bind="click: function() {$parent.deletedonut($data)}"/></td>
</tr>
Notice how I have data-bound the delete function and THIS WORKS!. but if I do the following:
<td><input type="button" value="Delete Donut" data-bind="click: {$parent.deletedonut($data)}"/></td>
well, this doesn't work. The delete function doesn't even get hit.
Can someone tell me what I'm doing wrong?
You only need to the function() ... syntax in your click binding if you want to pass additional parameter to your handler beside the $data. (see the documentation: Accessing the event object, or passing more parameters section)
But if your only parameter is $data then KO will automatically pass that in so you can just write:
<input type="button" value="Delete Donut"
data-bind="click: $parent.deletedonut"/>
Note: there is no need for the {} and you also don't need arguments as well ($data) because you are passing the $parent.deletedonut as the reference to that handler function.
But in itself this won't work in your case because you are using this in your handler to access your view model.
You have two options:
You can use bind: data-bind="click: $parent.deletedonut.bind($parent)" in this case you don't need to change your handler.
Demo JSFiddle
Or you can store a reference of the this in a variable like self and use that in your handler instead of the this.
So change your handler to:
var self = this;
this.deletedonut = function (item) {
self.donuts.remove(item);
}
Demo JSFiddle.