I have a table with select2 selections. Each row has an add button with a default value in the attribute. When the user adds an item each select2 box with the same default value has to be updated. Here is a part of my code:
<tr>
<td>
<div class="gb-select-div" rowId="279525">
<select class="idInLine">
<option value="">--Select--</option>
</select>
</div>
</td>
<td>
<a href='#' default="Piet" class='ui-icon ui-icon-circle-plus addId'></a>
</td>
</tr>
var rowId;
var def;
var newOption = new Option(name, newId, true, true);
$(".idInLine").each(function() {
rowId = $(this).closest('div').attr('rowId');
def = $('#tr' + rowId).find(".addId").attr("default")
if (def === defaultValue) {
$(this).append(newOption).trigger('change');
}
});
The code is almost working. A new item is added (Ajax). The select2 change event is triggered (selections are saved with Ajax). The only problem is; only one select2 control is showing the new value, the others keep showing "--Select--".
I am using the latest version of select2 v4.
Solved it. The line:
var newOption = new Option(name, newId, true, true);
had to be inside the each loop.
Related
I am new to ASP.NET MVC and not that great with Javascript/jQuery.
My end goal is to provide a Delete link to the user to delete a row from a table. I want to do it as a POST operation rather than a GET as this, as I understand, POST is best practice. I wanted to add a confirm dialog before deleting but I didn't want to use the ugly javascript confirm dialog box and I was having problems with the form submitting without waiting for the jQuery dialog box to be answered. So, I turned the submit button into a regular button and added an onclick event which calls a ConfirmDelete javascript method in which I display a custom jQuery confirmation dialog. If answered in the affirmative, I find the form by ID using the keys of the record that the user wants to delete (keys = vendor Id and Effective Date). Once ethe form is found, I use Javascript to submit the form.
-------------------
public static class DateTimeExtensions
{
public static long ToLong(this DateTime value)
{
return long.Parse(value.ToString("yyyyMMddHHmmss"));
}
}
---------------------------------------
#using (Html.BeginForm("Delete", "StateAssessment", new
{
vendorId = Model.VendorId,
effectiveDate = Model.EffectiveDate
},
FormMethod.Post,
new { #id = "Form_" + Model.VendorId + "_" + #Model.EffectiveDate.ToLong() }
))
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model.VendorId)
</td>
<td>
#Html.DisplayFor(modelItem => Model.EffectiveDate)
</td>
<td>
#Html.DisplayFor(modelItem => Model.LastTimeStamp)
</td>
<td>
#Html.ActionLink("Edit", "Edit",
new
{
vendorId = Model.VendorId,
effectiveDate = Model.EffectiveDate
})
<input value="Delete" class="btn btn-link" onclick="#string.Format("ConfirmDelete('{0}','{1}')", Model.VendorId, Model.EffectiveDate.ToLong())" />
</td>
</tr>
}
<script type="text/javascript">
function ConfirmDelete(vendorId, effectiveDate) {
var $myDialog = $('<div></div>')
.html('Are you sure that you want to delete this State Assessment?')
.dialog({
modal: true,
autoOpen: false,
title: 'Delete Confirmation',
buttons: {
"OK": function () {
$(this).dialog("close");
var form = $("#Form_" + vendorId + "_" + effectiveDate);
form.submit();
return true;
},
"Cancel": function ()
{
$(this).dialog("close");
return false;
}
}
});
$myDialog.dialog('open');
}
</script>
As you see, the ID of the form is constructed of the literal "Form_" concatenated with the vendor ID and EffectiveDate keys, where the EffectievDate value was normalized into a value that could be used in an ID.
This all worked, but man, it looks ugly to me and very long winded, especially when I think how easy this could be done in WinForms in a no more than few lines of code. I am looking for a better way. I'm thinking this code has noob written all over it and I'd like to denoob it.
Hi i want to create table that has as many rows as user can set in input field.
how to do that instead of 5 in for loop i have value specified in input tag ?
#Using (Html.BeginForm("AddNewProces", "Admin", FormMethod.Post))
#<input type="number" value="5" min="1" name="rowsNumber" />
#<table>
#For i As Integer = 0 To 5
#<tr>
<td>Row #i</td>
</tr>
Next i
</table>
End Using
EDIT:
Ok i decided to change some things but now it still doesent work ;/ this is what i try now:
<script type="text/javascript">
$('.rowsNumber').on('input', function () {
alert("Value Changed");
});
</script>
and here is my htlm.textboxfor
#Html.TextBoxFor(Function(m) m.NumberOfRows, New With {.class = "rowsNumber"})
You would need to do this client-side, not server-side. The server-side code can't read the value of the input before the page has even been rendered.
So your view markup would simplify:
#Using (Html.BeginForm("AddNewProces", "Admin", FormMethod.Post))
#<input type="number" value="5" min="1" name="rowsNumber" />
#<table id="myTable">
</table>
End Using
Then you'd attach a JavaScript handler to the input to modify the table. It might have a structure that's something like this:
$('input[name="rowsNumber"]').on('input', function () {
var existingRowCount = $('#myTable tr').length;
var newRowCount = parseInt($(this).val());
if (newRowCount == existingRowCount) {
return;
}
if (newRowCount > existingRowCount) {
// append new rows to the table
}
if (newRowCount < existingRowCount) {
// remove trailing rows from the table
}
});
Hi I have looked around online for hours trying to solve this but I couldn't find a solution.
I am building the solution using ASP.NET MVC and Knockout. The controller returns the options for the user to select from to the view which converts it into JSON and uses the mapping plugin to map it to a knockout View Model. It populates correctly because when I do this: ko.toJSON($data) to test it, the correct data is returned but the view won't update the list when an item is added to it.
My guess is that the properties aren't observables but I'm not sure how to fix that.
This is an example of the JSON Returned:
[{"Key":1,"Value":"company"}]
This is my javascript:
function ProjectWorkedOn() {
var self = this;
self.client = ko.observable();
self.job = ko.observable();
self.project = ko.observable();
self.workType = ko.observable();
}
function createTimesheetViewModel() {
var self = this;
//list of options
self.UserClients = ko.observableArray();
self.UserProjects = ko.observableArray();
self.UserJobs = ko.observableArray();
self.UserWorkTypes = ko.observableArray();
//keep track of selected options
self.selectedClient = ko.observable();
self.selectedProject = ko.observable();
self.selectedJob = ko.observable();
self.selectedWorkType = ko.observable();
//list to add choices in
self.ListProjectsWorkedOn = ko.observableArray();
self.addProjectWorkedOn = function () {
var project = new ProjectWorkedOn();
project.client = self.selectedClient;
project.job = self.selectedJob;
project.project = self.selectedProject;
project.workType = self.selectedWorkType;
self.ListProjectsWorkedOn.push(project)
}
self.removeProjectWorkedOn = function (projectWorkedOn) {
self.ListProjectsWorkedOn.remove(projectWorkedOn)
}
}
$(function () {
var CreateTimesheetViewModel = new createTimesheetViewModel();
CreateTimesheetViewModel.UserClients = ko.mapping.fromJSON('#Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.UserClients))');
CreateTimesheetViewModel.UserProjects = ko.mapping.fromJSON('#Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.UserProjects))');
CreateTimesheetViewModel.UserJobs = ko.mapping.fromJSON('#Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.UserJobs))');
CreateTimesheetViewModel.UserWorkTypes = ko.mapping.fromJSON('#Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.UserWorkTypes))');
ko.applyBindings(CreateTimesheetViewModel, document.getElementById("CreateTimesheet"));
});
This is the part of the view that adds items to the list:
<table>
<tr>
<td>
Projects Worked On:
</td>
<td>
Client: <select data-bind="options: UserClients, optionsText: 'Value', value: selectedClient"></select>
</td>
<td>
Project: <select data-bind="options: UserProjects, optionsText: 'Value', value: selectedProject"></select>
</td>
<td>
Job: <select data-bind="options: UserJobs, optionsText: 'Value', value: selectedJob"></select>
</td>
<td>
Service: <select data-bind="options: UserWorkTypes, optionsText: 'Value', value: selectedWorkType"></select>
</td>
<td>
<button data-bind="click: addProjectWorkedOn">Add Project</button>
</td>
</tr>
</table>
and this is what displays them:
<table>
<tr>
<td>Client</td>
<td>Project</td>
<td>Job</td>
<td>Service</td>
<td></td>
</tr>
<tbody data-bind="foreach: ListProjectsWorkedOn()">
<tr>
<td data-bind="text: client.Value"></td>
<td data-bind="text: project.Value"></td>
<td data-bind="text: job.Value"></td>
<td data-bind="text: workType.Value"></td>
<td><button data-bind="click: $parent.removeProjectWorkedOn">Remove</button></td>
</tr>
</tbody>
</table>
Thanks in advance!
EDIT:
I worked it out
to add project set the attributes like this: project.clientValue(self.selectedClient().Value);
then to reference them in view call it as a function: clientValue()
credit goes to Chris Patt for explaining that observables should be called as functions when you want to get their value
Because you're setting the ProjectWorkedOn observables and getting the selected values incorrectly. To set an observable you pass the value as a parameter as you would for a function and to get the value of an observable, you call it like a function. (They are in fact functions.):
self.addProjectWorkedOn = function () {
var project = new ProjectWorkedOn();
project.client(self.selectedClient());
project.job(self.selectedJob());
project.project(self.selectedProject());
project.workType(self.selectedWorkType());
self.ListProjectsWorkedOn.push(project)
}
EDIT
I was thinking you literally wanted the selected values, not the actual whole JSON object. What you're attempting simply isn't possible. The value of the select has to be an integer or string -- it can't be a full object. Usually you would handle something like this by first simply returning a value/text list to populate the selects, where the value would be something like the id. Then, upon selection, you would issue an AJAX request to retrieve the object with that id.
UPDATE: The third bullet below ("so I tried the following" section) is the closest I have come to a fix. I think I basically need to 1) disable the button, 2) add ui-disable, 3) jqm refresh, all within the data-bind or model.
I am trying to get one of the knockout demos to run with jqm in order to build something similar in my project. It mostly works except that the submit button does not disable goes disabled but does not appear grayed out if items = 0.
If you remove jqm, the example works fine and the button turns gray. I realize that jqm can conflict with knockout due to dom manipulation so I tried the following:
Triggering style refresh in the model methods: $('button').button(); or $('.ui-page-active' ).page( 'destroy' ).page();
Starting the binding after pageinit. This broke the entire thing.
As a test, I tried a data-bind to set ui-disable instead of disabling the button. It applies the class but jqm needs a refresh somehow. Can I put code into the data-bind to do the refresh?
<button data-bind="css: {'ui-disable': gifts().length > 0}" type='submit'>Submit</button>
Here is the fiddle I have been using to troubleshoot this: http://jsfiddle.net/wtjones/wkEgn/
What am I missing?
<form action='/someServerSideHandler'>
<p>You have asked for <span data-bind='text: gifts().length'> </span> gift(s)</p>
<table data-bind='visible: gifts().length > 0'>
<thead>
<tr>
<th>Gift name</th>
<th>Price</th>
<th />
</tr>
</thead>
<tbody data-bind='foreach: gifts'>
<tr>
<td><input class='required' data-bind='value: name, uniqueName: true' /></td>
<td><input class='required number' data-bind='value: price, uniqueName: true' /></td>
<td><a href='#' data-bind='click: $root.removeGift'>Delete</a></td>
</tr>
</tbody>
</table>
<button data-bind='click: addGift'>Add Gift</button>
<button data-bind='enable: gifts().length > 0' type='submit'>Submit</button>
</form>
The model code:
var GiftModel = function(gifts) {
var self = this;
self.gifts = ko.observableArray(gifts);
self.addGift = function() {
self.gifts.push({
name: "",
price: ""
});
};
self.removeGift = function(gift) {
self.gifts.remove(gift);
};
self.save = function(form) {
alert("Could now transmit to server: " + ko.utils.stringifyJson(self.gifts));
// To actually transmit to server as a regular form post, write this: ko.utils.postJson($("form")[0], self.gifts);
};
};
var viewModel = new GiftModel([
{ name: "Tall Hat", price: "39.95"},
{ name: "Long Cloak", price: "120.00"}
]);
ko.applyBindings(viewModel);
// Activate jQuery Validation
//$("form").validate({ submitHandler: viewModel.save });
Yep. If you change button properties via JS (or using KO to change these props), then you must call the refresh method to update visual styling.
$('button').button('refresh');
So I suggest to create custom binding instead of default enable that updates mobile button styling (if applied):
ko.bindingHandlers.mobileEnable = {
update: function(el) {
ko.bindingHandlers.enable.update.apply(el, arguments);
$.fn.button && $(el).button('refresh');
}
}
and...
<button data-bind='mobileEnable: gifts().length > 0' type='submit'>Submit</button>
Corrected fiddle: http://jsfiddle.net/wkEgn/2/
<tr>
#foreach (string s in "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15".Split(','))
{
<td>#Html.TextBox("Time","")
</td>
<p>
</p>
}
</tr>
How i get the values from textboxes created above using either javascript or jquery.
kindly assist me
Here it is:
$('input[name=Time]').each(function(index, element){
var txtValue = element.value;
});