ASP.NET MVC Knockout button click call POST API - javascript

I have a table (list) on my front end in html, and foreach row, I have a button:
...
<td>
<button data-bind="click: sendDataToApi">Test button</button>
</td>
...
and in the .js file I have something like this:
define(['viewmodels/shell', 'durandal/services/logger', 'plugins/dialog', 'viewmodels/shell', 'toastr', 'knockout', 'kovalidationconfig', 'plugins/router', 'typeahead.bundle'],
function (shell, logger, dialog, shell, toastr, ko, kvc, router, typeahead) {
var vm = {
activate: activate,
shell: shell,
data: ko.observableArray([]),
close: function () {
$(window).off('popstate', vm.goBack);
$(window).off('resize', adjustModalPosition);
dialog.close(vm, 'cancel');
},
goBack: function () {
$(window).off('popstate', vm.goBack);
$(window).off('resize', adjustModalPosition);
dialog.close(vm, 'back');
},
editPreregisteredChildren: function () {
router.navigate("#/function/" + this.id);
},
currentPage: ko.observable(1),
itemsPerPage: ko.observable(10),
hasNextPage: ko.observable(false),
previousPage: previousPage,
nextPage: nextPage,
sendDataToApi: function () {console.log("sdsdsds")},
searchCriteria: ko.observable(''),
applySearch: applySearch,
locations: ko.observableArray([]),
locationId: ko.observable(),
LocationName: ko.observable(),
exportHref: ko.observable("/spa/ExportSchedulings"),
bindingComplete: function (view) {
bindFindLocationEvent(view);
}
};
function sendDataToApi() {
console.log("hello.")
};
});
so, firstly, I want to get console.log("something") to work.
for now Im getting error in my console in chrome:
Uncaught ReferenceError: Unable to process binding "click: function(){return sendDataToApi }"
Message: sendDataToApi is not defined
I dont get it why?
after that I need to do an ajax call to my controller, and the end to call some api in that controller, and return the information if the api call was successfull or not.

I am going to assume that you are trying to display information in a table given the
<td>
<button data-bind="click: sendDataToApi">Test button</button>
</td>
I am also going to assume that that there is a ko:foreach at the table or table-body level. if that is the case then sendDataToApi is associated with the parent vm object and not the object that is currently being used to create the table rows.
If that is the case then you would need to use the $parent.sendDataToApi or $root.sendDataToApi
<td>
<button data-bind="click: $parent.sendDataToApi">Test button</button>
</td>
or
<td>
<button data-bind="click: $root.sendDataToApi">Test button</button>
</td>
EDIT
you just need to add a parameter to the receiving function because the knockout passes the current object.
var serverData = [{
id: 1,
name: 'Test 1'
},
{
id: 2,
name: 'Test 2'
},
{
id: 3,
name: 'Test 3'
},
];
function ViewModel() {
var self = this;
self.data = ko.observableArray([]);
self.checkServer = function checkServer(row) {
console.log(ko.toJS(row));
}
self.fillTable = function fillTable() {
var mappedData = serverData.map(r => new RowViewModel(r));
self.data(mappedData);
}
}
function RowViewModel(data) {
var self = this;
self.id = ko.observable(data.id || 0);
self.name = ko.observable(data.name || '');
}
ko.applyBindings(new ViewModel());
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<button class="button" data-bind="click: fillTable">Fill Table</button>
<table class="table">
<tbody data-bind="foreach: data">
<tr>
<td data-bind="text: id"></td>
<td data-bind="text: name"></td>
<td>
<button data-bind="click: $parent.checkServer">Check Server</button>
</td>
</tr>
</tbody>
</table>

Related

Validation message not appearing

On adding ko validation extender to dynamic objects it is not displaying the error message when showAllMessages() is called. There is also no span tag added below the respective controls which will show the error message.
I also like to show the error message just below the control as soon as the object is added to observable array.
Please find the fiddle
http://plnkr.co/edit/PUgxqrarDeaabDxUwgLO?p=preview
JavaScript
var schedule = function() {
var self = this;
self.name = ko.observable();
self.startDate = ko.observable();
self.endDate = ko.observable();
// Add validation
self.name.extend({required: {message: 'Name Required'}});
self.startDate.extend({required: {message: 'Start Date Required'}});
self.endDate.extend({required: {message: 'End Date Required'}});
}
var viewmodel = {
model: {
lookups: {
grandSlams: ["Australian Open", "French Open", "Wimbledon", "US Open"]
},
schedules: ko.observableArray(),
status: ko.observable()
},
actions: {
addSchedule: function() {
console.log('Add Called');
viewmodel.model.schedules.push(new schedule());
viewmodel.model.status('Edited');
console.log(viewmodel.model.schedules().length);
},
saveSchedule: function(){
console.log('Save Called');
var errors = ko.validation.group(viewmodel.model.schedules, { deep: true });
if (errors().length > 0) {
console.log(errors());
errors.showAllMessages();
hasError = true;
}
viewmodel.model.status('Saved!!!');
}
}
};
$(function() {
ko.validation.init({
insertMessages: true,
messagesOnModified: true,
grouping: {
deep: true, //by default grouping is shallow
observable: true //and using observables
}
});
ko.applyBindings(viewmodel);
});
HTML
<!DOCTYPE html>
<html>
<head>
<script data-require="jquery#*" data-semver="2.1.4" src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<script data-require="knockout#2.2.1" data-semver="2.2.1" src="//cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/knockout-min.js"></script>
<script data-require="knockout-validation#*" data-semver="1.0.2" src="//cdnjs.cloudflare.com/ajax/libs/knockout-validation/1.0.2/knockout.validation.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<h1>Knockout Validation!</h1>
<button data-bind="click: actions.addSchedule">Add Schedule</button>
<button data-bind="click: actions.saveSchedule">Save Schedule</button>
<h3>Schedules</h3>
<table>
<thead>
<tr>
<th>Grand Slams</th>
<th>Start</th>
<th>End</th>
</tr>
</thead>
<tbody data-bind="foreach:model.schedules">
<tr>
<td style="width:250px">
<select data-bind="options: $root.model.lookups.grandSlams, optionsCaption:'Select...'"></select>
</td>
<td style="width:250px">
<input type="text" data-bind="value: startDate" />
</td>
<td style="width:250px">
<input type="text" data-bind="value: endDate" />
</td>
</tr>
</tbody>
</table>
<h3 data-bind="text: model.status"></h3>
</body>
</html>
Updated example
You're missing the value binding on the select element. It should be
<select data-bind="value: name, options: $root.model.lookups.grandSlams, optionsCaption:'Select...'"></select>
Updated viewmodel if you want to validate on addSchedule (you can probably remove this.actions.showErrors() from save now, I left it just in case)
var viewmodel = {
model: {
lookups: {
grandSlams: ["Australian Open", "French Open", "Wimbledon", "US Open"]
},
schedules: ko.observableArray(),
status: ko.observable()
},
actions: {
addSchedule: function() {
console.log('Add Called');
viewmodel.model.schedules.push(new schedule());
viewmodel.model.status('Edited');
this.actions.showErrors();
console.log(viewmodel.model.schedules().length);
},
showErrors: function() {
var errors = ko.validation.group(viewmodel.model.schedules, { deep: true });
if (errors().length > 0) {
console.log(errors());
errors.showAllMessages();
hasError = true;
}
},
saveSchedule: function(){
console.log('Save Called');
var errors = ko.validation.group(viewmodel.model.schedules, { deep: true });
this.actions.showErrors();
viewmodel.model.status('Saved!!!');
}
}
};

Update UI after ajax response

I am new to knocokout.js so i have a table in which data is bind using ajax call.When user click on edit button row information is fill to a form which is on same page below the table.
after ajax call which update the data into database successfully , i am not able to show the changed value of particular object which is changed into table. If i refresh then its show new value .
Here is my html and js code .
<div id="body">
<h2>
Knockout CRUD Operations with ASP.Net Form App</h2>
<h3>
List of Products</h3>
<table id="products1">
<thead>
<tr>
<th>
ID
</th>
<th>
Name
</th>
<th>
Category
</th>
<th>
Price
</th>
<th>
Actions
</th>
</tr>
</thead>
<tbody data-bind="foreach: Products">
<tr>
<td data-bind="text: Id">
</td>
<td data-bind="text: Name">
</td>
<td data-bind="text: Category">
</td>
<td data-bind="text: formatCurrency(Price)">
</td>
<td>
<button data-bind="click: $root.edit">
Edit</button>
<button data-bind="click: $root.delete">
Delete</button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>
</td>
<td>
</td>
<td>
Total :
</td>
<td data-bind="text: formatCurrency($root.Total())">
</td>
<td>
</td>
</tr>
</tfoot>
</table>
<br />
<div style="border-top: solid 2px #282828; width: 430px; height: 10px">
</div>
<div data-bind="if: Product">
<div>
<h2>
Update Product</h2>
</div>
<div>
<label for="productId" data-bind="visible: false">
ID</label>
<label data-bind="text: Product().Id, visible: false">
</label>
</div>
<div>
<label for="name">
Name</label>
<input data-bind="value: Product().Name" type="text" title="Name" />
</div>
<div>
<label for="category">
Category</label>
<input data-bind="value: Product().Category" type="text" title="Category" />
</div>
<div>
<label for="price">
Price</label>
<input data-bind="value: Product().Price" type="text" title="Price" />
</div>
<br />
<div>
<button data-bind="click: $root.update">
Update</button>
<button data-bind="click: $root.cancel">
Cancel</button>
</div>
</div>
</div>
Code
function formatCurrency(value) {
return "$" + parseFloat(value).toFixed(2);
}
function ProductViewModel() {
//Make the self as 'this' reference
var self = this;
//Declare observable which will be bind with UI
self.Id = ko.observable("");
self.Name = ko.observable("");
self.Price = ko.observable("");
self.Category = ko.observable("");
var Product = {
Id: self.Id,
Name: self.Name,
Price: self.Price,
Category: self.Category
};
self.Product = ko.observable();
self.Products = ko.observableArray(); // Contains the list of products
// Initialize the view-model
$.ajax({
url: 'SProduct.aspx/GetAllProducts',
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: {},
success: function (data) {
// debugger;
$.each(data.d, function (index, prd) {
self.Products.push(prd);
})
//Put the response in ObservableArray
}
});
// Calculate Total of Price After Initialization
self.Total = ko.computed(function () {
var sum = 0;
var arr = self.Products();
for (var i = 0; i < arr.length; i++) {
sum += arr[i].Price;
}
return sum;
});
// Edit product details
self.edit = function (Product) {
self.Product(Product);
}
// Update product details
self.update = function () {
var Product = self.Product();
$.ajax({
url: 'SProduct.aspx/Update',
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: "{Product:" + ko.toJSON(Product) + "}",
success: function (data) {
console.log(data.d);
self.Product(null);
alert("Record Updated Successfully");
},
error: function (data) {
console.log(data);
}
})
}
// Cancel product details
self.cancel = function () {
self.Product(null);
}
}
$(document).ready(function () {
var viewModel = new ProductViewModel();
ko.applyBindings(viewModel);
});
and my webmethod which called by ajax request is as follow :
// to update product
[WebMethod]
public static testModel.Product Update(testModel.Product Product)
{
testEntities db = new testEntities();
var obj = db.Products.First(o => o.Id == Product.Id);
obj.Name = Product.Name;
obj.Price = Product.Price;
obj.Category = Product.Category;
db.SaveChanges();
return obj;
}
and JSON response of ajax call as follow
{"d":{"__type":"testModel.Product","Id":31,"Name":"12","Category":"12","Price":1350,"EntityState":2,"EntityKey":
{"EntitySetName":"Products","EntityContainerName":"testEntities","EntityKeyValues":
[{"Key":"Id","Value":31}],"IsTemporary":false}}}
Here's what's happening. Here: self.Products.push(prd) prd is just a plain javascript object with plain property values, nothing is observable. You're pushing the raw object onto the Products observableArray, which updates the DOM because Products was changed and KO is watching it. When you click 'edit', you set self.Product to that plain object and the KO updates the DOM with this object and its values because Product was changed and KO is watching it. So now your Product form below displays, you see the information, and it looks like you can edit the properties but KO won't update those property changes because KO isn't watching them. They're not observable. Change:
$.each(data.d, function (index, prd) {
//self.Products.push(prd);
self.Products.push({
Id: ko.observable(prd.Id),
Name: ko.observable(prd.Name),
Price: ko.observable(prd.Price),
Category: ko.observable(prd.Category)
});
});
General helpful tips
<div data-bind="if: Product">
This only evaluates once when you bind the viewModel to the DOM with ko.applyBindings. Since self.Product has an initial value of null KO removes this altogether.*Note: I was thinking of #if for some reason.
This works like the visible binding except when the value is false, the element and its children are removed from the DOM. So there is more DOM manipulation going on than necessary. You probably just want to hide this <div>
I would recommend changing this to:
<div data-bind="visible: Product">
Instead of this:
<input type="text" data-bind="text: Product().Name" />
<input type="text" data-bind="text: Product().Category" />
<input type="text" data-bind="text: Product().Price" />
Try this instead:
<div data-bind="with: Product">
<input type="text" data-bind="text: Name" />
<input type="text" data-bind="text: Category" />
<input type="text" data-bind="text: Price" />
</div>
Consider renaming self.Product to self.SelectedProduct to make it more clear what it is for.
I'm not sure what this is doing in the ViewModel:
//Declare observable which will be bind with UI
self.Id = ko.observable("");
self.Name = ko.observable("");
self.Price = ko.observable("");
self.Category = ko.observable("");
var Product = {
Id: self.Id,
Name: self.Name,
Price: self.Price,
Category: self.Category
};
You don't use them in the DOM. You were kind of on the right path with this though. Instead, before the ProductViewModel, create this:
function ProductModel(data) {
var self = this;
data = data || {};
self.Id = ko.observable(data.Id);
self.Name = ko.observable(data.Name);
self.Price = ko.observable(data.Price);
self.Category = ko.observable(data.Category);
}
Now instead of:
$.each(data.d, function (index, prd) {
self.Products.push({
Id: ko.observable(prd.Id),
Name: ko.observable(prd.Name),
Price: ko.observable(prd.Price),
Category: ko.observable(prd.Category)
});
});
We can just do this:
$.each(data.d, function (index, prd) {
self.Products.push(new ProductModel(prd));
});
Hopefully that will get you headed in the right direction.
There is something to change:
Replace
$.each(data.d, function (index, prd) {
self.Products.push(prd);
})
With:
$.each(data.d, function (index, prd) {
self.Products.push({
Id: ko.observable(prd.Id),
Name: ko.observable(prd.Name),
Price: ko.observable(prd.Price),
Category: ko.observable(prd.Category)
});
})
Use ko.observable to make your properties notify the view of its changes so that the view can update accordingly. This should work but not perfect because this is 2 way binding, so whenever you update the values in your div, the view model object is updated immediately and even if your ajax fails to update the data in backend, making the data out of synch between client side and server side.
For better solution. You need to have a look at protectedObservable
$.each(data.d, function (index, prd) {
self.Products.push({
Id: ko.protectedObservable(prd.Id),
Name: ko.protectedObservable(prd.Name),
Price: ko.protectedObservable(prd.Price),
Category: ko.protectedObservable(prd.Category)
});
})
Inside your self.update ajax success function, trigger a change:
success: function (data) {
var product =self.Product();
product.Id.commit();
product.Name.commit();
product.Price.commit();
product.Category.commit();
self.Product(null);
alert("Record Updated Successfully");
}
And revert if there is error:
error: function (data) {
product.Id.reset();
product.Name.reset();
product.Price.reset();
product.Category.reset();
}
Update:
Remember to change all the places with Product.Property to Product.Property() to get its property value . For example: arr[i].Price should be changed to arr[i].Price()
Add self.Products.push(data.d); to the update() functions success handler.
success: function (data) {
console.log(data.d);
self.Product(null);
self.Products.push(data.d);
alert("Record Updated Successfully");
},
You need to update the array so that it reflects in bound html.

Binding Knockout.JS viewmodel to jQuery dialog

I have a jQuery modal dialog inside which I would like to pass data from a Knockout viewmodel. The dialog works fine as is - however, below code is broken.
Ideally, I would like to be able to click on the URI that triggers the modal dialog, and have the dialog load the data from the Knockout viewmodel. Any help would be greatly appreciated.
Markup:
List Names
<div id="listNames" data-bind="dataModel: { autoOpen: false, modal: true }">
<div>
<form action=''>
<p>You have added <span data-bind='text: name().length'> </span>
person(s)</p>
<table data-bind='visible: name().length > 0'>
<thead>
<tr><th>Select</th>
<th>Name</th>
<th>Age</th>
<th />
</tr>
</thead>
<tbody data-bind='foreach: metrics'>
<tr>
<td><input type="checkbox" /></td>
<td><span data-bind='text: name' > </span></td>
<td><span data-bind='text: age'> </span></td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
ViewModel:
var dataModel = function (edata) {
var self = this;
self.edata = ko.observableArray(edata);
self.addname = function () {
self.edata.push({
name: "",
age: ""
});
};
self.removename = function (name) {
self.edata.remove(name);
};
self.save = function (form) {
alert("Could now transmit to server: "
+ ko.utils.stringifyJson(self.edata));
// To actually transmit to server as a regular form post, write this:
// ko.utils.postJson($("form")[0], self.edata);
};
};
var viewModel = new dataModel([
{ name: "Jack", age: "41" },
{ name: "Jill", age: "33" }
]);
ko.applyBindings(new viewModel);
jQuery Dialog:
$("#listNames, ").dialog({
autoOpen: false,
width: 300,
modal: true,
buttons: {
"OK": function () {
$(this).dialog("destroy");
},
Cancel: function () {
$(this).dialog("close");
}
}
});
$("#openList")
.click(function () {
$("#listNames").dialog("open");
});
There are a few errors in the code you posted.
I have a working version here : http://jsfiddle.net/uFgz8/1/
Here is the HTML :
Open dialog //you had 2 elements with the same ID, I removed the ID on the link and bound it to a method in the view model
<div id="listNames"> <div>
<form action=''>
<p>You have added <span data-bind='text: name.length'> </span> person(s)</p> // name item is not observable, so you cannot use name().length
<table data-bind='visible: name.length > 0'> // same remark for name
<thead>
<tr>
<th>Select</th>
<th>Name</th>
<th>Age</th>
<th />
</tr>
</thead>
<tbody data-bind='foreach: edata'>
<tr>
<td>
<input type="checkbox" />
</td>
<td><span data-bind='text: name'> </span>
</td>
<td><span data-bind='text: age'> </span>
</td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
The JS:
$("#listNames").dialog({
autoOpen: false,
width: 300,
modal: true,
buttons: {
"OK": function () {
// do something
$(this).dialog("close"); // I replaced destroy by close, so it can be opened after ok has been clicked
},
Cancel: function () {
$(this).dialog("close");
}
}
});
var dataModel = function (edata) {
var self = this;
self.edata = ko.observableArray(edata);
self.addname = function () {
self.edata.push({
name: "",
age: ""
});
};
self.openDialog = function () {
$("#listNames").dialog("open");
};
self.removename = function (name) {
self.edata.remove(name);
};
self.save = function (form) {
alert("Could now transmit to server: " + ko.utils.stringifyJson(self.edata));
// To actually transmit to server as a regular form post, write this: ko.utils.postJson($("form")[0], self.edata);
};
};
var viewModel = new dataModel([{
name: "Jack",
age: "41"
}, {
name: "Jill",
age: "33"
}]);
ko.applyBindings(viewModel); // you have created a variable viewModel with data, but you bound ko with a new object of type viewModel, you must either call ko with viewModel you created, or inline the creation of a new "dataModel"
edit : I added some comments to my changes
edit 2 : I updated the link to the jsfiddle to get to the correct version ;)

Cascading select2 Combobox with Knockout JS

Here's the code: http://jsfiddle.net/W4qPT/
the combobox script is included at the bottom, if you remove it, everything works fine.
I cannot seem to get it to refresh the combobox with the new content given to me by the Knockout Ajax.
HTML
<div>
<div class="cbp-content" id="didScreen">
<div>
<table width='100%'>
<thead>
<tr>
<th width='25%'>State</th>
<th width='25%'>City</th>
<th class='quantity' width='10%'>Quantity</th>
<th width='10%'></th>
</tr>
</thead>
<tbody data-bind="foreach: items">
<tr>
<td>
<select class="combobox" data-bind="options: $parent.states, optionsText: 'name', value: state, optionsCaption: 'Select State'"></select>
</td>
<td>
<select class="combobox" data-bind="options: cities, optionsText: 'rc_abbr', optionsValue: 'id', value: city"></select>
</td>
<td>
<input name="quantity" data-bind="value: quantity" />
</td>
<td>
<button class="btn" data-bind="click: $parent.remove"><i class="icon-remove"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
<button class="btn" data-bind="click: newItem">Add Item</button>
</div>
</div>
</fieldset>
JavaScript (Knockout JS)
var Item = function () {
var self = this;
self.state = ko.observable();
self.city = ko.observable();
self.quantity = ko.observable();
self.cities = ko.observableArray([]);
self.state.subscribe(function (state) {
self.city("");
self.cities.removeAll();
$.ajax({
url: '/echo/json/',
type: 'POST',
data: {
json: ko.toJSON([{"id":"29","rc_abbr":"ANCHORAGE"}]),
},
success: function (response) {
self.cities(response);
}
});
});
};
var ViewModel = function (states) {
var self = this;
self.states = states;
self.items = ko.observableArray([new Item()]);
self.newItem = function () {
self.items.push(new Item());
};
self.remove = function (item) {
self.items.remove(item);
};
};
var usStates = [{
name: 'ALASKA',
abbreviation: 'AK'
}];
window.vm = new ViewModel(usStates);
ko.applyBindings(window.vm, document.getElementById('didScreen'));
$(".combobox").select2();
You have to call .select2() again on all new comboboxes you create. You're now only calling it on comboboxes that exist when your DOM is ready.
You could change this:
self.newItem = function () {
self.items.push(new Item());
};
To this:
self.newItem = function () {
self.items.push(new Item());
$(".combobox").not('.select2-container').select2();
};

Knockout.js: Updation of label element not reflecting in JSON source

I am new to knockout.JS. I am binding a JSON collection to a table.
<tbody data-bind="foreach: Collection">
<tr>
<td>
<span data-bind="text: FirstName" ></span>
</td>
<td>
<span data-bind="text: LastName" ></span>
</td>
<td>
<input type="button" data-bind="click: function(){ obj.RemoveItem($data) }" value="Del" />
</td>
<td>
<input type="button" data-bind="click: function(){ obj.SaveItems($data.Id) }" value="Edit/Save" />
</td>
</tr>
</tbody>
function viewModel(collection) {
var self = this;
this.Collection = ko.observableArray(collection);
this.AddItem = function() {
this.Collection.push({FirstName:"", LastName:""});
};
this.RemoveItem = function(data) {
this.Collection.remove(data);
};
this.SaveItems = function(id) {
alert("New Collection: " + ko.utils.stringifyJson(self.Collection));
}
};
var obj = new viewModel([
{ Id: 1,FirstName: "John", LastName: "Saleth" },
{ Id: 2, FirstName: "John", LastName: "Kennedy" }
]);
ko.applyBindings(obj);
In eachrow, I kept a edit button which on click, inserts a textbox in all TD's with value of
span. And on save click, i am updating the values of span elements with the values of textbox.
The problem is new values of span element is not reflecting in JSON collection. How to update the JSON source with updated span values on click of save button?
You should make each property of the Collection array observable as well.
function ItemModel(item) {
this.Id = ko.observable(item.Id);
this.FirstName = ko.observable(item.FirstName);
this.LastName = ko.observable(item.LastName);
};
function viewModel(collection) {
var self = this;
this.Collection = ko.observableArray();
ko.utils.arrayForEach(collection, function (i) { self.Collection.push(new ItemModel(i)); });
this.AddItem = function() {
this.Collection.push(new ItemModel({
FirstName: "",
LastName: ""
}));
};
...
};

Categories

Resources