I am facing the issue while binding the value for dropdown from a observable array.
Model
function question(item)
{
var self = this;
self.questionId = ko.observable(item.questionId || "");
self.position = ko.observable(item.position || "");
self.position.subscribe(function (data) {
// Some Logic
}, this, 'beforeChange');
api.position.subscribe(function (data) {
// Some Logic
}
}
View Model
function viewmodel(item)
{
var self = this;
self.questionList = ko.observableArray([]);
self.questionEntity = ko.observable(new question(item));
// initially Item will be blank
self.addQuestion = function(data)
{
data.position(self.questionList().length + 1);
self.questionList.push(data);
}
}
View
<div>
question Id : <input type="text" data-bind="value: questionEntity().questionId " >
<button data-bind='click: $root.addquestion'>Add Question</button>
</div>
<table>
<tbody data-bind='foreach: questionList '>
question Id : <span data-bind='text:questionId' ></span>
position :
<select data-bind='options: $root.positionList,optionsText: "id",optionsValue: "id" ,value: position'></select>
</tbody>
</table>
Problem
I have one popup div(addQuestion) and I will add the question. and I am keep on adding that question to my observable Array(questionList)
When i add First question my value in observable array is
questionId | Position
1 | 1
When I add second record
questionId | Position
1 | 1
2 | 2
When I Add thrid record, all the previous records POSITION value(value is binded to dropdown) is being reset to 1 except last record
questionId | Position
1 | 1
2 | 1
3 | 3
fourth record
questionId | Position
1 | 1
2 | 1
3 | 1
4 | 4
after debugging I found out its problem with two way binding with Dropdown
<select data-bind='options: $root.positionList,optionsText: "id",optionsValue: "id" ,value: position'></select>
in above code if change the binding(single way) like below it works fine
<select data-bind='options: $root.positionList,optionsText: "id",optionsValue: "id" ,value: position()'></select>
But I need to subscribe an event for the dropdown.
Related
I created a filter section using DataTables API and it seems working fine, except for the Status column that has Select List Options.
The filter function is searching every option that contains in Select List, but I want it to search only the first option in Select List.
For example: when I input 'Manual', I need it to filter only the first row, not a second row that got options value 'Manual' in it.
Before filter:
After filter:
HTML Code (in DataTable)
#if (dealer.STATUS == "R" || dealer.STATUS == "M")
{
<td class="tdStaff" data-label="Status">
#if(#Model.SelectLists.Where(x => x.Value == dealer.STATUS).Select(x => x.Value).First() == "M")
{
<select name="statusname">
<option value="M">Manual Pay</option>
<option value="R">Reject</option>
</select>
}
else if (#Model.SelectLists.Where(x => x.Value == dealer.STATUS).Select(x => x.Value).First() == "R")
{
<select name="statusname">
<option value="R">Reject</option>
<option value="M">Manual Pay</option>
</select>
}
</td>
}
else
{
<td>#dealer.STATUS_NAME</td>
}
Filter Function
function addSearchControl(json) {
$("#myTable thead").append($("#myTable thead tr:first").clone());
$("#myTable thead tr:eq(1) th").each(function(index) {
$(this).replaceWith('<th><input type="text" placeholder="' + $(this).html() + '..." style="width:100%"></input></th>');
var searchControl = $("#myTable thead tr:eq(1) th:eq(" + index + ") input");
searchControl.on('keyup', function() {
dataTable.column(index).search(searchControl.val()).draw();
});
});
}
Expect this to filter value only the first option in Select List.
Hope you understand and any advice would be grateful, Thanks.
I want to emty a cell based on the value in another cell. Both cells are custom rendered components
ie.
**comp1**
<div class="form-group input-group-sm">
<input
autocomplete="off"
class="form-control"
[(ngModel)]="value"
name="value"
type="number"
(ngModelChange)="updateMyData($event)"
[disabled]="disableDrpdwn()"
onkeypress="return (event.charCode >= 48 && event.charCode <= 57)"
onkeydown="return (event.keyCode!=13);"
(input)="onlyNumbers($event)"
/>
</div>
....
agInit(params: any): void {
this.params = params;
this.value = this.params.value;
}
disableDrpdwn() {
return this.params.data.amortizationPeriod === null || this.params.data.amortizationPeriod === 0;
}
updateMyData(data) {
this.params.data.amortizationPeriod = data;
if (this.params.data.amortizationPeriod === null || +this.params.data.amortizationPeriod === 0 ) {
this.params.data.amortizationMethod = null;
}
}
**comp2**
<div class="form-group input-group-sm dropdownSel">
<select #input [(ngModel)]="value" (ngModelChange)="updateMyData($event)" [disabled]= "disableDrpdwn()" class="form-control">
<option *ngFor="let item of dropdownnonInVal" [value]="item.name">{{ item.name}}</option>
</select>
</div>
....
agInit(params: any): void {
this.params = params;
this.value = this.params.value;
this.dropdownnonInVal = [{
name: 'Select',
value: ''
},
{
name: 'Yield Based',
value: 1
},
{
name: 'Price Based',
value: 2
}
];
}
updateMyData(data) {
this.params.data.amortizationMethod = data;
}
Here comp2 is dependent on comp1. So if I change the value of comp1's cell to 0, the value in the comp2's cell should be empty. i.e. the dropdown should get reset to blank on UI. How can I do it? Ngmodelchange is not doing any good. But the disable works properly. It the comp2 cell is disabled when the comp1 cell is 0 but the value is not getting blank. Need help.
I faced same issue in ag-grid. I guess there's no such functionality provided by AG Grid but obviously there's a workaround to it. You just need to empty the source (the cell you want to be emptied as in this.cellRenderer in image link) from which you're populating data in cellEditorParams (the cell you're changing values as in this.cellEditorParams in image link). Then put your logic in cellRenderer (the cell you want to be emptied as in this.cellRenderer in image link) as callback function.
image description here
Getting started with knockout, I have been playing with the pattern found at http://knockoutjs.com/examples/cartEditor.html. I have cascading select menus where the second one's options depend on the state of the first -- no problem so far. But whatever I do, I haven't figured a way to change the out-of-the-box behavior whereby the second element is not visible -- not rendered, I would imagine -- until the first element has a true-ish value (except by taking out the optionsCaption and instead stuffing in an empty record at the top of my data -- more on that below.) The markup:
<div id="test" class="border">
<div class="form-row form-group">
<label class="col-form-label col-md-3 text-right pr-2">
language
</label>
<div class="col-md-9">
<select class="form-control" name="language"
data-bind="options: roster,
optionsText: 'language',
optionsCaption: '',
value: language">
</select>
</div>
</div>
<div class="form-row form-group">
<label class="col-form-label col-md-3 text-right pr-2">
interpreter
</label>
<div class="col-md-9" data-bind="with: language">
<select class="form-control" name="interpreter"
data-bind="options: interpreters,
optionsText : 'name',
optionsCaption: '',
value: $parent.interpreter"
</select>
</div>
</div>
</div>
Code:
function Thing() {
var self = this;
self.language = ko.observable();
self.interpreter = ko.observable();
self.language.subscribe(function() {
self.interpreter(undefined);
});
};
ko.applyBindings(new Thing());
my sample data:
roster = [
{ "language": "Spanish",
"interpreters": [
{"name" : "Paula"},
{"name" : "David"},
{"name" : "Humberto"},
{"name" : "Erika"},
{"name" : "Francisco"},
]
},
{"language":"Russian",
"interpreters":[{"name":"Yana"},{"name":"Boris"}]
},
{"language":"Foochow",
"interpreters":[{"name":"Lily"},{"name":"Patsy"}]
},
/* etc */
Now, I did figure out that I can hack around this and get the desired effect by putting
{ "language":"", "interpreters":[] }
at the front of my roster data structure, and that's what I guess I will do unless one of you cognoscenti can show me the more elegant way that I am overlooking.
After using both Knockout and Vuejs, I found Vuejs much easier to work with. Knockout is a bit out dated and no longer supported by any one or group.
Having said that, here is how I addressed your issue. The comments here refer to the link you provided not your code so I could build my own test case.
My working sample is at http://jsbin.com/gediwal/edit?js,console,output
I removed the optionsCaption from both select boxes.
Added the following item to the data (note that this has to be the first item in the arry):
{"products":{"name":"Waiting", "price":0}, "name":"Select..."},
I added the disable:isDisabled to the second selectbox cause I want it to be disabled when nothing is selected in the first selectbox.
added self.isDisabled = ko.observable(true); to the cartline model
altered the subscription to check the new value. If it is the select option the second one gets lock.
function formatCurrency(value) {
return "$" + value.toFixed(2);
}
var CartLine = function() {
var self = this;
// added this to enable/disable second select
self.isDisabled = ko.observable(true);
self.category = ko.observable();
self.product = ko.observable();
self.quantity = ko.observable(1);
self.subtotal = ko.computed(function() {
return self.product() ? self.product().price * parseInt("0" + self.quantity(), 10) : 0;
});
// Whenever the category changes, reset the product selection
// added the val argument. Its the new value whenever category lchanges.
self.category.subscribe(function(val) {
self.product(undefined);
// check to see if it should be disabled or not.
self.isDisabled("Select..." == val.name);
});
};
var Cart = function() {
// Stores an array of lines, and from these, can work out the grandTotal
var self = this;
self.lines = ko.observableArray([new CartLine()]); // Put one line in by default
self.grandTotal = ko.computed(function() {
var total = 0;
$.each(self.lines(), function() { total += this.subtotal() })
return total;
});
// Operations
self.addLine = function() { self.lines.push(new CartLine()) };
self.removeLine = function(line) { self.lines.remove(line) };
self.save = function() {
var dataToSave = $.map(self.lines(), function(line) {
return line.product() ? {
productName: line.product().name,
quantity: line.quantity()
} : undefined
});
alert("Could now send this to server: " + JSON.stringify(dataToSave));
};
};
I am working on already developed code in AngularJS with Rails.
I am having a code which prints all the workflow states like not_found, in_process, new etc;
<td>
<div class="editable-wrapper">
<a e-name="states" e-ng-options="s.id as s.name for s in workflowStates" editable-select="address.workflowState" onbeforesave="updateAddress({workflowState: $data}, address)">{{ address.workflowState | capitalise }}</a>
</div>
</td>
Now with the above code {{ address.workflowState | capitalise }}, the page is showing as In_process, New etc;
My aim is to remove the underscores and display them as In process/ in process, Not found / not found etc. (Capitalize is not essential but have to remove underscore).
You can create a filter and use like:
HTML:
<a e-name="states" e-ng-options="s.id as s.name for s in workflowStates" editable-select="address.workflowState" onbeforesave="updateAddress({workflowState: $data}, address)">{{address.workflowState | removeUnderscores}}</a>
Filter:
filterExample.filter('removeUnderscores', function () {
return function (text) {
var str = text.replace(/_/g, ' ');
return str
};
})
DEMO FIDDLE
Here's a One Liner
<a e-name="states" e-ng-options="s.id as s.name for s in workflowStates" editable-select="address.workflowState" onbeforesave="updateAddress({workflowState: $data}, address)">{{address.workflowState.split("_").join(" ")}}</a>
DEMO FIDDLE FOR ONE LINER
You can use this filter (Disclaimer: I'm the author) that does exactly what you need.
{{ address.workflowState | capitalize:'first':'_' }}
If you want to implement it by yourself it could be something like this:
angular.module('angular-capitalize-filter',[])
.filter('capitalize', function () {
return function (input) {
if (!input) {
return input;
}
// Capitalize the first letter of a sentence
var output = input.charAt(0).toUpperCase() + input.slice(1).toLowerCase();
return output.split('_').join(' ');
}
});
And then use it as:
{{ address.workflowState | capitalize }}
You can create your own filter for replacing _ with space as bellow
angular.module('your-module-name', [])
.filter('stateformat', function() {
return function(input) {
if(input != null && input.length > 0)
return input.replace('_', ' ');
}
});
HTML
<td>
<div class="editable-wrapper">
<a e-name="states" e-ng-options="s.id as s.name for s in workflowStates" editable-select="address.workflowState" onbeforesave="updateAddress({workflowState: $data}, address)">{{ address.workflowState | capitalise | stateformat }}</a>
</div>
</td>
I would like to ask for your help to make some code modifications to some code I am working on.
Currently the code displays 'x' number of products on a page in the fashion of:
box 1 (product id 140)
price $10
box 2 (product id 140)
price $10
box 3 (product id 143) - different Id
price $20
Order Sub-Total: $40.00
CODE
<div class="yourorder">
#foreach (var prod in Model.Products)
{
for (var i = 0; i < prod.Count; i++)
{
<div data-index="#i" data-type="product" data-id="#prod.ID" data-multiple="#prod.Multiple" data-multiplecatid="#prod.MultipleCategoryID">
#{Html.RenderAction("ShoppingCartProduct", "ShoppingCart", new { id = prod.ID });}
<div class="shippingArea">
<div class="shippingPickerLabel">Use this shipping address:</div>
<div>
<select class="shippingPicker" data-type="prod" data-id="#(prod.ID)">
<option value="-1">Add New</option>
</select>
</div>
</div>
</div>
<br />
<hr />
}
}
<div class="totals" style="font-weight:normal;margin-top:20px;">
#if (Model.TotalPriceFrom == Model.TotalPriceTo)
{
<div><strong>Order Sub-Total:</strong> $<span class="grandTotal">#Model.TotalPriceTo.ToString("0.00")</span></div>
}
else
{
<div><strong>Order Sub-Total:</strong> $<span class="grandTotal">#Model.TotalPriceFrom.ToString("0.00") - $#Model.TotalPriceTo.ToString("0.00")</span></div>
}
</div>
</div>
The Price is calculated in a PartialView named "ShoppingCartProduct". the code that does that:
CODE
<div class="shoppingCartPrice">
#if (Model.Prod.HasRange && Model.Prod.WeightFrom.HasValue && Model.Prod.WeightTo.HasValue)
{
if (Model.Prod.UnitID.HasValue)
{
<div>$#Model.Prod.Price.Value.ToString("0.00") per #Model.UnitName</div>
}
<div>Price: $#((Model.Prod.Price.Value * Model.Prod.WeightFrom.Value).ToString("0.00")) - $#((Model.Prod.Price.Value * Model.Prod.WeightTo.Value).ToString("0.00"))</div>
<div style="display:none;" class="minPrice">#((Model.Prod.Price.Value * Model.Prod.WeightFrom.Value).ToString("0.00"))</div>
<div style="display:none;" class="maxPrice">#((Model.Prod.Price.Value * Model.Prod.WeightTo.Value).ToString("0.00"))</div>
}
else
{
<div>Price: $#Model.Prod.Price.Value.ToString("0.00")</div>
<div style="display:none;" class="minPrice">#((Model.Prod.Price.Value).ToString("0.00"))</div>
<div style="display:none;" class="maxPrice">#((Model.Prod.Price.Value).ToString("0.00"))</div>
}
</div>
I need help in making it calculate different and display different too.
Like:
box 1 qty 2 (products with same id)
price each $10
sub-total $20.00
box 2 qty 1 (products with different id)
price $20
sub-total $20.00
Order Sub-Total: $40.00
I had the same problem not that long ago. We solved it by using a cookie.
The products were loaded from an SQL server, but for each product we increased it's ID with 1, so the product ID ranged from 1 to X. With the thought of a huge webshop, we made this number 4 charters long, so: 0001.
Then we just read the product ID into a string and added the quantity behind that, so a string of 6 chars. Then:
int count = Response.Cookie["producten"].Length / 6
for (int i = 0; i < count; i++)
{
//paste your string decoder here to sort out the product ID and the quantity
Panel p = new Panel();
p.ID = i;
p.CssClass = [your cssclass]
//paste here code for the rest of your div
cartdiv.Controls.Add(p);
}
By doing this, the code generates a div (or anything else you'd want) with unique ID's and the same Class, for each product.