Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I have a feeling that this isn't going to be a simple problem (or may be associated with something entirely un-related) but I'm going to take a shot. I have an ASP.NET MVC page that also uses KnockOutJS. There are two related drop-downs on the page. The first one presents a list of Offer Types. Depending on which Offer Type you choose, the second drop-down needs to re-populate with the correct options for that Offer Type.
This used to work at some point in time, but the page is under heavy construction and now not working. When I select a new Offer Type, the other dropdown doesn't repopulate.
Here is the HTML for the DropDowns. You'll notice there is a hidden input there. When I select a new OfferType, this correctly populates with the OfferTypeId.
<div class="control-group" style="clear: both;">
#Html.LabelFor(m => m.OfferType, new { #class = "control-label" })
<div class="controls">
<select class="input-block-level" id="OfferType" name="OfferType" data-bind="options: offerTypes, value: selectedOfferType, optionsText: 'DisplayName'"></select>
</div>#Html.HiddenFor(m => m.OfferTypeId, new { data_bind = "value: selectedOfferType().OfferTypeId" })
</div>
<div class="control-group" style="clear: both;">
#Html.LabelFor(m => m.OfferTypeDetails, new { #class = "control-label" })
<div class="controls">
<select class="input-block-level" id="OfferTypeDetails" name="OfferTypeDetails" data-bind="options: offerDetails, value: selectedOffer, optionsText: 'DisplayName'"></select>
</div>#Html.HiddenFor(m => m.OfferTypeDetailsTypeId, new { data_bind = "value: selectedOffer().OfferTypeId" })
</div>
And here is the Javascript (data trimmed for brevity):
$(document).ready(function () {
var offerType = function (offerTypeId, displayName, offerTypeDetailsTypes) {
var self = this;
self.OfferTypeId = offerTypeId;
self.DisplayName = displayName;
self.OfferTypeDetailsTypes = offerTypeDetailsTypes;
};
var offerTypeDetailsType = function (offerTypeDetailsTypeId, displayName, offerTypeId) {
var self = this;
self.OfferTypeDetailsTypeId = offerTypeDetailsTypeId;
self.DisplayName = displayName;
self.OfferTypeId = offerTypeId;
};
function viewModel() {
var self = this;
self.selectedOfferType = ko.observable();
self.selectedOffer = ko.observable();
self.offerTypes = ko.observableArray([
new offerType('1', 'Purchase Discount'),
new offerType('2', 'Savings'),
...
]);
self.offerTypeDetailsTypes = ko.observableArray([
new offerTypeDetailsType('1', 'Spend $10 Get $1 Off', '1'),
new offerTypeDetailsType('2', 'Spend $100 Get 10% Off', '1'),
new offerTypeDetailsType('3', '$ Half Off', '2'),
...
]);
self.offerDetails = ko.computed({
read: function () {
var activeCategories = ko.observableArray();
ko.utils.arrayForEach(self.offerTypeDetailsTypes(), function (item) {
if (item.OfferTypeId == self.selectedOfferType().OfferTypeId)
activeCategories.push(item);
});
return activeCategories();
} , deferEvaluation: true
});
}
ko.applyBindings(new viewModel());
}
Todd, I was able to get your example code working without any problems. I just coppied to jsFiddle and remove the MVC Razor and jquery stuff.
http://jsfiddle.net/zrDtU/
The html
<select class="input-block-level" id="OfferType" name="OfferType" data-bind="options: offerTypes, value: selectedOfferType, optionsText: 'DisplayName'"></select>
<select class="input-block-level" id="OfferTypeDetails" name="OfferTypeDetails" data-bind="options: offerDetails, value: selectedOffer, optionsText: 'DisplayName'"></select>
The javascript
//I can't post a link to jsFiddle without code
var offerType = function (offerTypeId, displayName, offerTypeDetailsTypes) {
var self = this;
self.OfferTypeId = offerTypeId;
self.DisplayName = displayName;
self.OfferTypeDetailsTypes = offerTypeDetailsTypes;
};
var offerTypeDetailsType = function (offerTypeDetailsTypeId, displayName, offerTypeId) {
var self = this;
self.OfferTypeDetailsTypeId = offerTypeDetailsTypeId;
self.DisplayName = displayName;
self.OfferTypeId = offerTypeId;
};
function viewModel() {
var self = this;
self.selectedOfferType = ko.observable();
self.selectedOffer = ko.observable();
self.offerTypes = ko.observableArray([
new offerType('1', 'Purchase Discount'),
new offerType('2', 'Savings')
]);
self.offerTypeDetailsTypes = ko.observableArray([
new offerTypeDetailsType('1', 'Spend $10 Get $1 Off', '1'),
new offerTypeDetailsType('2', 'Spend $100 Get 10% Off', '1'),
new offerTypeDetailsType('3', '$ Half Off', '2')
]);
self.offerDetails = ko.computed({
read: function () {
var activeCategories = ko.observableArray();
ko.utils.arrayForEach(self.offerTypeDetailsTypes(), function (item) {
if (item.OfferTypeId == self.selectedOfferType().OfferTypeId) activeCategories.push(item);
});
return activeCategories();
},
deferEvaluation: true
});
}
ko.applyBindings(new viewModel());
It looks like your issue is elsewhere.
Related
I am trying to make the helper #Html.EnumDropDownListFor searchable with an input tag on it. That way I can type to search for an item in the huge list. I preferably want to make this hard coded without other plugins. Can someone help me?
Here is the code:
<div>Escolha aqui o banco de sua preferência:</div>
#Html.EnumDropDownListFor(model => model.BankPaymentMethods, " ", htmlAttributes: new {#class = "form-control"})
The EnumDropDownListFor helper only generates <select> elements. The closest you can get without a plugin would be an input with a datalist and the list attribute.
Assuming your enum is called BankPaymentMethod and BankPaymentMethods is an IEnumerable of some sort, and your model has a PaymentMethod property:
#Html.TextBoxFor(m => m.PaymentMethod, new { #class = "form-control", list = "payment-methods" })
<datalist id="payment-methods">
#foreach(var method in Model.BankPaymentMethods)
{
<option value="#method">#method</option>
}
</datalist>
For reference: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist.
Typically its done inside a text box, I guess you can do it inside a Select by appending the value and name also you need to paste your VM or selectList VMModel. I have made some assumptions, code is not tested, but with a couple change and hopefully it will help you.
#Html.TextBoxFor(model => model.BankPaymentID)
#section scripts{
// you can update to the latest version of Jquery-ui, I put in the most compatible version for you
<script src="~/Scripts/jquery-ui-1.15.1.js">script>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.15.1/themes/base/jquery-ui.css">
<script>
$(function () {
$("#BankPaymentID").autocomplete({
source: function (request, response) {
$.ajax({
url: '#Url.Action("Searchable")', // server action
datatype: "json",
data: {
term: request.term // this what you are searching
},
success: function (data) {
response($.map(data, function (val, item) {
return {
label: val.Name,
value: val.Name,
BankPaymentID: val.ID
}
}))
}
})
},
select: function (event, ui) {
$.get("/Home/GetBankPaymentMethods", { BankPaymentID: ui.item.BankPaymentID }, function (data) {
$("#PaymentID").empty();
$.each(data, function (index, row) {
$("#PaymentID").append("<option value='" + row.PaymentID + "'>" + row.PaymentName + "option>")
});
});
}
})
})
script>
}
Controller Searchable Action
public ActionResult Searchable(string term)
{
if (!String.IsNullOrEmpty(term))
{
var list = db.banks.Where(c=>c.PaymentName.ToUpper().Contains(term.ToUpper())).Select(c => new { Name = c.PaymentName, ID = c.BankPaymentID })
.ToList();
return Json(list, JsonRequestBehavior.AllowGet);
}
else
{
var list = db.banks.Select(c => new { Name = c.PaymentName, ID = c.BankPaymentID })
.ToList();
return Json(list, JsonRequestBehavior.AllowGet);
}
}
Im tryinf to validate this input field when i click on Submit button. What happens is when I click on the submit button and the textbox is empty it alert thank you,however it should alert Please check your submission
Html
<div id="newTest">
<fieldset>
<div class="row">
<label>Last name:</label>
<input type="text" data-bind="value: lastName" />
</div>
</fieldset>
<fieldset>
<button type="button" data-bind='click: submit'>Submit</button>
</fieldset>
</div>
Javascript
<script src="~/Scripts/knockout-3.5.0.js"></script>
<script src="~/Scripts/knockout.validation.min.js"></script>
<script>
var viewModel = function () {
ko.validation.rules.pattern.message = 'Invalid.';
ko.validation.init({
registerExtenders: true,
messagesOnModified: true,
insertMessages: true,
parseInputAttributes: true,
messageTemplate: null
}, true);
var self = this;
self.lastName = ko.observable().extend({ required: true }),
self.submit = function () {
if (viewModel.errors().length === 0) {
alert('Thank you.');
}
else {
alert('Please check your submission.');
viewModel.errors.showAllMessages();
}
};
};
viewModel.errors = ko.validation.group(viewModel);
var viewModel2 = new viewModel();
ko.applyBindings(viewModel2, document.getElementById("newTest"));
</script>
Since you are initializing viewModel2 as new viewModel(), these two lines of code:
viewModel.errors = ko.validation.group(viewModel);
var viewModel2 = new viewModel();
should be:
var viewModel2 = new viewModel();
viewModel.errors = ko.validation.group(viewModel2);
It's also unclear to me why you wrote this the way you did. It could be simpler IMO. Here's an example (JSFiddle: https://jsfiddle.net/vwuazfg0/):
ko.validation.rules.pattern.message = 'Invalid.';
ko.validation.init({
registerExtenders: true,
messagesOnModified: true,
insertMessages: true,
parseInputAttributes: true,
messageTemplate: null
}, true);
var viewModel = {
lastName : ko.observable().extend({ required: true }),
submit : function () {
if (viewModel.errors().length === 0) {
alert('Thank you.');
}
else {
alert('Please check your submission.');
viewModel.errors.showAllMessages();
}
}
};
viewModel.errors = ko.validation.group(viewModel);
ko.applyBindings(viewModel, document.getElementById("newTest"));
I am having an issue with the angular ui bootstrap datepicker popup (https://angular-ui.github.io/bootstrap/) where I cannot get my model to update.
I have in place 2 different calendars - one with the popup and one without (uib-datepicker-popup and uib-datepicker) inside one of my angular component.
This is my code:
function headerCtrl () {
const self = this;
self.$onInit = () => {
self.dateOptions = {
showWeeks: false,
formatYear: 'yyyy',
startingDay: 1
};
self.today = function() {
self.calendar_date2 = new Date();
};
self.today();
self.clear = function() {
self.calendar_date2 = null;
};
self.inlineOptions = {
customClass: getDayClass,
minDate: new Date(),
showWeeks: true
};
self.toggleMin = function() {
self.inlineOptions.minDate = self.inlineOptions.minDate ? null : new Date();
self.dateOptions.minDate = self.inlineOptions.minDate;
};
self.toggleMin();
self.open = function() {
self.popup.opened = true;
};
self.setDate = function(year, month, day) {
self.calendar_date2 = new Date(year, month, day);
};
self.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate'];
self.format = self.formats[0];
self.altInputFormats = ['M!/d!/yyyy'];
self.popup = {
opened: false
};
var tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
var afterTomorrow = new Date();
afterTomorrow.setDate(tomorrow.getDate() + 1);
self.events = [
{
date: tomorrow,
status: 'full'
},
{
date: afterTomorrow,
status: 'partially'
}
];
function getDayClass(data) {
var date = data.date,
mode = data.mode;
if (mode === 'day') {
var dayToCheck = new Date(date).setHours(0,0,0,0);
for (var i = 0; i < self.events.length; i++) {
var currentDay = new Date(self.events[i].date).setHours(0,0,0,0);
if (dayToCheck === currentDay) {
return self.events[i].status;
}
}
}
}
self.changeCalendarDate = () => {
console.log('changeCalendarDate');
console.log(self.calendar_date);
};
self.changeCalendarDate2 = () => {
console.log('changeCalendarDate2');
console.log(self.calendar_date2);
};
}}
export default {
bindings: {
duration: "<",
zoom: "<",
selection: "<",
selections: "<",
calendar_date: "<",
onDurationChange: "&",
onCalendarDateChange: "&",
onHeatmapSelectionChange: "&"
},
controller: headerCtrl,
template: `
<div class="pp-header-container">
<div uib-datepicker
ng-model="$ctrl.calendar_date"
datepicker-options="$ctrl.dateOptions"
class="heatmap-header pp-sch-header-item"
ng-change="$ctrl.changeCalendarDate()"></div>
<div class="pp-header-calendar">
<input type="text"
uib-datepicker-popup="{{$ctrl.format}}"
ng-model="$ctrl.calendar_date2"
is-open="$ctrl.popup.opened"
datepicker-options="$ctrl.dateOptions"
ng-required="true"
close-text="Close"
alt-input-formats="$ctrl.altInputFormats"
maxlength="10"
size="10"
ng-change="$ctrl.changeCalendarDate2()" />
<button type="button" class="btn btn-default" ng-click="$ctrl.open()"><i class="glyphicon glyphicon-calendar"></i></button>
</div>
</div>`
}
http://prnt.sc/esq9c9
The calendar on the left (uib-datepicker) works, as soon as I pick a date, it triggers changeCalendarDate() and it prints the selected date (console.log(self.calendar_date);)
Now what I am trying to do is change calendar as I would like the one with the popup ( uib-datepicker-popup ) which does trigger changeCalendarDate2() but when I print the value (console.log(self.calendar_date2);) it is undefined.
I am sure I need to grab that value differently but I don't know how.
Can anyone help?
Thanks :)
I have solved this problem :D
The problem was this
uib-datepicker-popup="{{$ctrl.format}}"
as soon as I have removed thee value assigned and left only
uib-datepicker-popup
it worked. I don't know why but I am happier now :)
I am very new to knockoutjs. I try to modified a little from [knockoutjs sample] (http://knockoutjs.com/documentation/options-binding.html) but it didn't work.
<select data-bind="option: availCustomers, optionsText: 'CustomerName',
value: selectedCustomer, optionsCaption: '--- Choose ---'">
</select>
and the viewmodel :
<script>
function customerViewModel() {
var self = this;
self.availCustomers = ko.observableArray();
self.selectedCustomer = ko.observable();
};
var Customer = function (id, name) {
this.CustomerId = id;
this.CustomerName = name;
};
$(document).ready( function() {
var cvm = new customerViewModel();
cvm.availCustomers = new ko.observableArray([
new Customer("12345", "ABC"),
new Customer("54321", "XYZ")
]);
ko.applyBindings(cvm);
});
</script>
so please guide me
I think this is just a mispeling error, the parameter to bind is called "options".
<select data-bind="options: availCustomers, optionsText: 'CustomerName',
value: selectedCustomer, optionsCaption: '--- Choose ---'">
</select>
attached the file EXAMPLE: http://jsfiddle.net/brux88/9fzG4/1/
hi,
I'm starting to use knockoutjs in an asp.net mvc project.
i have a view :
<button data-bind='click: load'>Load</button>
<table>
<thead>
<tr>
<th>Cliente</th>
<th>Colli</th>
<th>Tara</th>
<th>Peso Tara</th>
<th> </th>
</tr>
</thead>
<tbody data-bind='foreach: righe'>
<tr>
<td>
<select data-bind="
value: selectedCli,
options: clienteList,
optionsText: function(item) { return item.Rscli + '-' + item.Codcli },
optionsCaption: '--Seleziona un Cliente--'"
style=" width: 150px">
</select>
</td>
<td >
<input data-bind='value: Ncolli' />
</td>
<td>
<select data-bind="value: selectedTara,
options: taraList,
optionsText: function(item) { return item.Destara +
'-' + item.Codtara},
optionsCaption: '--Seleziona un Cliente--'"
style=" width: 150px">
</select>
</td>
<td >
<input data-bind="value: Ptara" />
</td>
<td>
<a href='#' data-bind='click: $parent.rimuoviRiga'>Elimina</a>
</td>
</tr>
</tbody>
</table>
<button data-bind='click: aggiungiRiga'>Aggiungi</button>
<button data-bind='click: salva'>Salva</button>
<button data-bind='click: annulla'>Annulla</button>
my result from data db:
[{"Codcli":4,"Rscli":"antonio","Codtart":"1002","Despar":"ciliegino","Ncolli":10,"Pcolli":100,"Codtara":"03","Destara":"","Ptara":82,"Pnetto":18,"Prezzo":1},{"Codcli":1,"Rscli":"bruno","Codtart":"1001","Despar":"pomodoro","Ncolli":10,"Pcolli":100,"Codtara":"03","Destara":"","Ptara":10,"Pnetto":90,"Prezzo":1}]
my viewmodel knockoutjs:
<script type="text/javascript">
var listCli= [{Codcli: 1,Rscli: "Bruno"},{Codcli: 2,Rscli: "Pippo"},{Codcli: 3,Rscli: "Giacomo"}];
var listTa= [{Codtara: 01,Destara: "Plastica",Pertara:4},{Codtara: 02,Destara: "Legno",Pertara:6},{Codtara: 03,Destara: "Ploto",Pertara:8}];
var mydataserver = [{"Codcli":3,"Rscli":"Giacomo","Ncolli":10,"Codtara":"03","Destara":"Legno","Ptara":82},{"Codcli":1,"Rscli":"Bruno","Ncolli":10,"Codtara":"02","Destara":"Plastica","Ptara":10}];
var RigaOrdine = function () {
var self = this;
self.selectedCli = ko.observable();
self.clienteList = ko.observableArray(listCli);
self.Ncolli = ko.observable();
self.selectedTara = ko.observable();
self.taraList = ko.observableArray(listTa);
self.Ptara = ko.observable();
self.Ncolli.subscribe(function () {
self.Ptara(self.Ncolli() ? self.selectedTara().Pertara * self.Ncolli() : 0);
});
self.selectedTara.subscribe(function () {
self.Ptara(self.Ncolli() ? self.selectedTara().Pertara * self.Ncolli() : self.selectedTara().Pertara);
});
};
var Ordine = function () {
var self = this;
self.righe = ko.observableArray([new RigaOrdine()]); // Put one line in by default
// Operations
self.aggiungiRiga = function () {
self.righe.push(new RigaOrdine());
};
self.rimuoviRiga = function (riga) {
self.righe.remove(riga);
};
self.salva = function() {
var righe = $.map(self.righe(), function (riga) {
return riga.selectedCli() ? {
Codcli: riga.selectedCli().Codcli,
Rscli: riga.selectedCli().Rscli,
Ncolli: riga.Ncolli(),
Codtara: riga.selectedTara().Codtara,
Ptara: riga.Ptara(),
} : undefined;
});
alert( ko.toJSON(righe));
//save to server
/* $.ajax({
url: "/echo/json/",
type: "POST",
data: ko.toJSON(righe),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function(data) {
}
});*/
self.righe([new RigaOrdine()]);
};
//load from server
self.load = function() {
$.ajax({ url: '/echo/json/',
accepts: "application/json",
cache: false,
statusCode: {
200: function (data) {
alert(ko.toJSON(mydataserver));
//i do not know apply to viewmodel
},
401: function (jqXHR, textStatus, errorThrown) {
alert('401: Unauthenticated');
// self.location = "../../Account/Login.html?returnURL=/Index.html";
}
}
});
};
self.annulla = function() {
self.righe([new RigaOrdine()]);
};
};
var viewmodel = new Ordine();
ko.applyBindings(viewmodel);
</script>
if I want to load data from a db, how do I? Whereas there are dropdownlist
Your question is a bit weak so I will give you a more general answer.
To answer your question regarding how to load data from a db, it looks like that you have started on the right track. Usually you use an AJAX request to do the async request of data. To do this, knockoutJS provides the following function:
$.getJSON("/some/url", function(data) {
// Now use this data to update your view models,
// and Knockout will update your UI automatically
})
Source: http://knockoutjs.com/documentation/json-data.html
In the callback provided you will have access to the data returned from the server. It depends on the logic of your application what you want to do here - for some applications it might make sence to update the state of the viewmodel to make corresponding updates in the view.
If your question is more specific, please elaborate. Otherwise, I hope I got you on the right track.
As i can see.. you may want some good pratice to load.
I'll share with you mine.
Well.. return a Json as an JsonResult.
// POST: /Client/LoadClient
[HttpPost]
public JsonResult LoadClient(int? id)
{
if (id == null) return null;
var client = _business.FindById((int) id);
return Json(
new
{
id = cliente.id,
name = cliente.name,
list = cliente.listOfSomething.Select(s => new {idItemFromList = s.idWhatever, nameItemFromList = s.nameWhatever})
});
}
JS
viewmodel.Client.prototype.LoadClient= function (id) {
var self = this;
if (id == 0) {
return null;
}
$.ajax({
url: actionURL("LoadClient", "Client"),
data: { id: parseInt(id) },
dataType: "json",
success: function (result) {
if (result != null)
self.Load(result);
}
});
Load method.
viewmodel.Client.prototype.Load = function (result) {
var self = this;
self.idClient(result.id);
self.nameCliente(result.name);
self.ListOfSomething(result.list);
};
and..
ko.applyBinding(yourModel);
as u can see I'm using prototype it's a good practice too.