Knockout dropdown form binding - json

I have a html form for adding multiple addresses:
http://i48.tinypic.com/jg2ruo.png
This way If I change the Address Type selection the entire form has to bind to the correct json address object:
var jsonAddresses = { Addresses:
[
{ AddressType: 1, Address1: "", Address2: "",Province:"",City:"",State:"",PostalCode:"",Municipal:"" },
{ AddressType: 2, Address1: "", Address2: "",Province:"",City:"",State:"",PostalCode:"",Municipal:"" },
{ AddressType: 3, Address1: "", Address2: "",Province:"",City:"",State:"",PostalCode:"",Municipal:"" },
{ AddressType: 4, Address1: "", Address2: "",Province:"",City:"",State:"",PostalCode:"",Municipal:"" }
]
};
I have done this with Jquery with a lot of code actually but I want to know how can I do this with Knockout. The idea is instead of having a fixed json object with the 4 types of addresses i want to have only 1 json object and if I select an address type that is not in the array then the object is added and binded, if the address type already exists in the array then just bind it. then i can have a "remove" link that when clicked the selected address type object is removed from the array.
Thanks in advance.

I'm guessing a little bit on this, because its not entirely clear. You want a single form for editing addresses, with a dropdown that lets you select which address you are editing. I've put a working fiddle together, but here are the important parts.
You have a concept of an Address object, which is observable since you will be updating the values. Then you need a viewmodel to keep track of all the address, have some concepted of the selected address, and the ability to add new addresses. This is the part that wasn't clear, so I just went with a New Address button. Let me know if you have something else in mind. Other than the list of states, and the initial address data (both which should come from the server) this is all the code, and as you can see knockout makes it pretty simple.
HTML:
<select data-bind="options: addresses, optionsText: 'typeName', value: selectedAddress"></select>
<div data-bind="with: selectedAddress">
Name: <input data-bind="value: typeName" /></br>
Line1: <input data-bind="value: address1" /></br>
Line2: <input data-bind="value: address2" /></br>
City: <input data-bind="value: city" /></br>
State: <select data-bind="options: $parent.states, value: state"></select></br>
Postal Code: <input data-bind="value: postalCode" />
</div>
<button data-bind="click: addAddress">New Address</button>
<button data-bind="click: deleteAddress">Remove Address</button>
​
ViewModels:
var Address = function(address) {
this.id = ko.observable(address.AddressType || 0);
this.typeName = ko.observable(address.TypeName || '');
this.address1 = ko.observable(address.Address1 || '');
this.address2 = ko.observable(address.Address2 || '');
this.city = ko.observable(address.City || '');
this.state = ko.observable(address.State || '');
this.postalCode = ko.observable(address.PostalCode || '');
};
var App = function(addressList) {
var self = this;
self.states = states;
self.addresses = ko.observableArray(ko.utils.arrayMap(addressList,
function(i) { return new Address(i); }
));
self.selectedAddress = ko.observable(self.addresses[0]);
self.addAddress = function() {
var newId = self.addresses()[self.addresses().length -1].id + 1;
var newAddress = new Address({AddressType: newId});
self.addresses.push(newAddress);
self.selectedAddress(newAddress);
};
self.deleteAddress = function() {
self.addresses.remove(self.selectedAddress());
self.selectedAddress(self.addresses[0]);
};
};
EDIT1: added remove button. This is for the demo, obviously you will want some safety logic when the array is empty.

Related

How create a new input field row by clicking a button reactjs

I am building an ecommerce app and I want to collect the users different phone numbers and address.
I want to create a new field where the user types new phone number and address
I tried using state to accomplish the task but I am geting error
TypeError: contactInfo.phoneInputs is undefined
const RegisterModal = ({openRegisterModal, setOpenRegisterModal}) => {
const [contactInfo, setContactInfo] = useState({
phoneInputValue : {},
phoneInputs: [],
addressInputValue : {},
addressInputs: [],
})
console.log(contactInfo)
const addContact = (e) => {
e.preventDefault()
const contactsphoneInfo = "phoneNumber";
const contactsAddressInfo = "address";
let phoneInputBox =
<Input name={contactsphoneInfo} star="false" label="PhoneNumber" type="text" className="col-md-6" />
let addressInputBox =
<Input name={contactsAddressInfo} star="false" label="address" type="text" className="col-md-6" />
setContactInfo(contactInfo.phoneInputs.push({phoneInputBox}))
console.log(contactInfo)
}
return (
<div>
{
contactInfo.phoneInputs.map(input => input)
}
button onClick={addContact}>Add</button>
</div>
)
}
export default RegisterModal
How do I fix this error
link to codesandbox
https://codesandbox.io/s/distracted-morse-s6zn0
your setstate is a bit fishy, I believe
setContactInfo({...contactInfo, phoneInputs: [...contactInfo.phoneInputs,phoneInputBox ]});
This should work . but i recommend you try for more clean code .
and console.log(contactInfo) before render if you check itll be undefined if you want to check the inital value still use useEffect then log it .

Select tag not working properly with Anuglar

I'm building a form using Angular.
in my form, there is a type of select as a tag.
Below is my code:
<div class="form-group" ng-class="{ 'has-error': form.$submitted && form['{{field.id}}'].$invalid }" ng-if="field.type === 'select'">
<select>
<div class="" ng-repeat="value in field.values">
<option value="">{{value.title}}</option>
</div>
</select>
</div>
And here is json file for field.values:
"values": [
{
"id": 0,
"title": "Not Selected"
},
{
"id": 1,
"title": "Yes"
},
{
"id": 2,
"title": "No"
}
]
Javascript(changes made):
app.controller('I129Ctrl', ['$scope', '$http', 'JSONModelsService',
function ($scope, $http, JSONModelsService) {
var formData = {};
$scope.groups = [];
$scope.sections = [];
$scope.fields = [];
//below is basically equivalent to routing
JSONModelsService.get(['test', 'Valid Passport'])
.then(function (response) {
console.log(response);
// $scope.group = response.data.groups[0];
$scope.groups = response.data.groups;
$scope.sections = $scope.groups.sections;
$scope.fields = $scope.groups.sections.fields;
});
Basically, I first check whether field.type is equal to select. If so, I want to values in select type of question. However, it is not working as I imagine. What am I doing wrong?
First don't use a div element in a select this can't work. You can put ng-repeat in option level but this won't work since you don't have ng-model binded with this.
The way of doing it is the directive ng-options in select tag.
<select ng-model="valueSelected" ng-options="value as value.title for value in field.values"></select>
If you want to let your user being able to not select/unselect a value. Add in the select the following option :
<option ng-value="null">-- No value--</option>

sapui5 data from json

Have problem to read data from json. My login.json file
{
"Users": [
{
"login" : "admin",
"password" : "admin"
}
]
}
Here is my login.xml.view
<core:View
controllerName="sap.ui.demo.myFiori.view.login"
xmlns="sap.m"
xmlns:l="sap.ui.layout"
xmlns:core="sap.ui.core" >
<Page
title="{i18n>LoginIn}">
<VBox
class="marginBoxContent" >
<items>
<Label text="User" />
<Input
id="nameInput"
type="Text"
placeholder="..." />
<Label text="password" />
<Input
id="passwInput"
type="Password"
placeholder=" ..." />
<Text id="description" class="marginOnlyTop" />
<Button text="Login" press="handleContinue" />
</items>
</VBox>
</Page>
</core:View>
and login.controller.js
jQuery.sap.require("sap.ui.demo.myFiori.util.Formatter");
sap.ui.controller("sap.ui.demo.myFiori.view.login", {
handleContinue : function (evt) {
var name = this.getView().byId("nameInput").getValue();
var paswd = this.getView().byId("passwInput").getValue();
if (name == "log" && paswd == "pass") {
var context = evt.getSource().getBindingContext();
this.nav.to("Master", context);
}
else {
jQuery.sap.require("sap.m.MessageToast");
sap.m.MessageToast.show("Wrong login");
}
}
});
This login screen works, but I can't get login and password from json file and currently these data are taken from if sentence, which is not good. Any suggestions?
First, I am assuming that this is just a test app, as having the correct plain text auth credentials actually in the client app is rather bad practice ...
The crux of your question seems to be: "How can I access JSON data from a file?"
There is a Q&A already on SO with that theme: How to get data from a json file? but if you want to use a model, which is a common practice in UI5 apps, then you could:
1) Create a JSON model, specifying the name of the JSON file; the JSONModel mechanism will take care of the loading; assign this to the view
this.getView().setModel(new sap.ui.model.json.JSONModel('login.json'), "login");
2) Access the data in the JSON model when you need to check, using the getData() method
// Note - extremely bad practice - don't do this for real!
var authinfo = this.getView().getModel("login").getData().Users[0];
if (name == authinfo.login && paswd == authinfo.password) {
....
(I'm indexing 0 of Users as you seem to have your authinfo inside an array)
Maybe I defined something wrong before but now it works. I changed login.controller.js. Now it looks like this:
jQuery.sap.require("sap.ui.demo.myFiori.util.Formatter");
sap.ui.controller("sap.ui.demo.myFiori.view.login", {
onInit: function () {
var oModels = new sap.ui.model.json.JSONModel("login.json");
sap.ui.getCore().setModel(oModels);
},
handleContinue : function (evt) {
var authinfo = this.getView().getModel().getData().Users[0];
var name = this.getView().byId("nameInput").getValue();
var paswd = this.getView().byId("passwInput").getValue();
if (name == authinfo.login && paswd == authinfo.passw) {
var context = evt.getSource().getBindingContext();
this.nav.to("Master", context);
}
else {
jQuery.sap.require("sap.m.MessageToast");
sap.m.MessageToast.show("Wrong login");
}
}
});

Hiding radio options depending on other seperate radio option in knockout [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I plan to have two sets of radio options on my form, one radio called Operating System and another radio called Database.
The option selected by the Operating System radio dictates the values available for selection in the Database radio group.
In my json object the requires field indicates the visibility of the option when the sku of the Operating System is selected. If no requires field is provided for a database option, then it will always be available regardless of the selected operating system.
How would one approach this in knockout, or do I need to rethink my approach?
My jsfiddle is here
var osOptions = [{
name: "Windows Standard",
sku: "201",
},{
name: "Windows Enterprise",
sku: "202",
}, {
name: "CentOS Linux",
sku: "203",
}, {
name: "Debian",
sku: "204",
}];
var databaseOptions = [{
name: None,
}, {
name: "SQL Express",
sku: 401,
requires: ["201", "202"]
}, {
name: "SQL Standard",
sku: 402,
requires: ["202"]
}, {
name: "MySQL",
sku: "MySQL1",
requires: ["201", "202", "203"]
}, {
name: "RavenDb",
sku: 403,
}, {
name: "MongoDB",
sku: 404,
requires: ["204"]
}];
function viewModel() {
this.os = osOptions;
this.database = databaseOptions;
this.selectedOs = ko.observable();
this.selectedDb = ko.observable();
}
ko.applyBindings(new viewModel);
<!- view html -->
<h1>Select OS:</h1>
<div data-bind="foreach: os" >
<div>
<input type="radio" name="optionsGroup" data-bind="attr: {value: name}, checked: $root.selectedOs" />
<span data-bind="text: name"></span>
</div>
</div>
<h1>Select Db</h1>
<div data-bind="foreach: database" >
<div>
<input type="radio" name="optionsGroup" data-bind="attr: {value: name}, checked: $root.selectedDb" />
<span data-bind="text: name"></span>
</div>
</div>
I would create a different computed collection availableDatabases where
first I would look up the currently selected OS
then I would use the ko.utils.arrayFilter to filter out the databases where the the requires array does not contain the selected sku.
So I would write something like this:
this.availableDatabases = ko.computed(function() {
var selectedOsName = this.selectedOs();
var selectedOs = ko.utils.arrayFirst(this.os, function(os){
return os.name == selectedOsName;
}, this);
if (!selectedOs)
return [];
return ko.utils.arrayFilter(this.database, function(db){
return db.requires && db.requires.indexOf(selectedOs.sku) > -1;
}, this)
}, this);
And use this new collection in the view:
<div data-bind="foreach: availableDatabases" >
<div>
<input type="radio" name="optionsGroup"
data-bind="attr: {value: name}, checked: $root.selectedDb" />
<span data-bind="text: name"></span>
</div>
</div>
Demo JSFiddle.
Note If you have the sku instead of the name as the value for you first radio buttons:
<input type="radio" name="optionsGroup"
data-bind="attr: {value: sku}, checked: $root.selectedOs" />
Then there is no lookup needed in the computed because selectedOs would contain the sku property directly (Demo)...
Take a look at this fiddle
You can create an computed that retrieves the available databases.
JS :
function viewModel() {
var self = this;
this.os = osOptions;
this.database = databaseOptions;
this.selectedOs = ko.observable();
this.selectedDb = ko.observable();
this.availableDatabase = ko.computed(function () {
var osSku = self.selectedOs();
return ko.utils.arrayFilter(self.database, function (dbItem) {
if (osSku == null) return false;
if (dbItem.requires == null) return true;
var dbs = ko.utils.arrayFirst(dbItem.requires, function (requiredOS) {
return requiredOS == osSku;
}) != null;
return dbs;
});
});
};
ko.applyBindings(new viewModel);
I hope it helps.

I cannot get my jqGrid to populate

Edited with working code as per Mark's answer below.
I'm really starting to loath MVC. I have been trying all day to get a simple grid to work, but I'm having more luck banging a hole in my desk with my head.
I'm trying to implement a search page that displays the results in a grid. There are 3 drop-down lists that the user can use to select search criteria. They must select at least one.
After they have searched, the user will be able to select which records they want to export. So I will need to include checkboxes in the resulting grid. That's a future headache.
Using JqGrid and Search form - ASP.NET MVC as a reference I have been able to get the grid to appear on the page (a major achievement). But I can't get the data to populate.
BTW, jqGrid 4.4.4 - jQuery Grid
here is my view:
#model Models.ExportDatex
<script type="text/javascript">
$(document).ready(function () {
$('#btnSearch').click(function (e) {
var selectedSchool = $('#ddlSchool').children('option').filter(':selected').text();
var selectedStudent = $('#ddlStudent').children('option').filter(':selected').text();
var selectedYear = $('#ddlYear').children('option').filter(':selected').text();
var selectedOption = $('#exportOption_1').is(':checked');
if (selectedSchool == '' && selectedStudent == '' && selectedYear == '') {
alert('Please specify your export criteria.');
return false;
}
selectedSchool = (selectedSchool == '') ? ' ' : selectedSchool;
selectedStudent = (selectedStudent == '') ? ' ' : selectedStudent;
selectedYear = (selectedYear == '') ? ' ' : selectedYear;
var extraQueryParameters = {
school: selectedSchool,
student: selectedStudent,
year: selectedYear,
option: selectedOption
};
$('#searchResults').jqGrid({
datatype: 'json',
viewrecords: true,
url: '#Url.Action("GridData")?' + $.param(extraQueryParameters),
pager: '#searchResultPager',
colNames: ['SchoolID', 'Student Name', 'Student ID', 'Apprenticeship', 'Result'],
colModel: [
{ name: 'SchoolID' },
{ name: 'Student Name' },
{ name: 'StudentID' },
{ name: 'Apprenticeship' },
{ name: 'Result' }]
}).trigger('reloadGrid', [{ page: 1 }]);
});
});
</script>
#using (Html.BeginForm("Index", "Datex", FormMethod.Post))
{
<h2>Export to Datex</h2>
<div class="exportOption">
<span>
#Html.RadioButtonFor(model => model.ExportOption, "true", new { id = "exportOption_1" })
<label for="exportOption_1">VET Results</label>
</span>
<span>
#Html.RadioButtonFor(model => model.ExportOption, "false", new { id = "exportOption_0" })
<label for="exportOption_0">VET Qualifications</label>
</span>
</div>
<div class="exportSelectionCriteria">
<p>Please specify the criteria you want to export data for:</p>
<table>
<tr>
<td>School:</td>
<td>#Html.DropDownListFor(model => model.SchoolID, Model.Schools, new { id = "ddlSchool" })</td>
</tr>
<tr>
<td>Student: </td>
<td>#Html.DropDownListFor(model => model.StudentID, Model.Students, new { id = "ddlStudent" })</td>
</tr>
<tr>
<td>Year Completed:
</td>
<td>
#Html.DropDownListFor(model => model.YearCompleted, Model.Years, new { id = "ddlYear" })
</td>
</tr>
</table>
<table id="searchResults"></table>
<div id="searchResultPager"></div>
</div>
<div class="exportSearch">
<input type="button" value="Search" id="btnSearch" />
<input type="submit" value="Export" id="btnExport" />
</div>
}
Here is my Controller. As we don't have a database yet, I am just hardcoding some results while using an existing table from a different DB to provide record IDs.
[HttpGet]
public JsonResult GridData(string sidx, string sord, int? page, int? rows, string school, string student, string year, string option)
{
using (SMIDbContainer db = new SMIDbContainer())
{
var ds = (from sch in db.SCHOOLs
where sch.Active.HasValue
&& !sch.Active.Value
&& sch.LEVEL_9_ORGANISATION_ID > 0
select sch).ToList();
var jsonData = new
{
total = 1,
page = 1,
records = ds.Count.ToString(),
rows = (
from tempItem in ds
select new
{
cell = new string[]{
tempItem.LEVEL_9_ORGANISATION_ID.ToString(),
tempItem.SCHOOL_PRINCIPAL,
"40161",
"No",
"Passed (20)"
}
}).ToArray()
};
return Json(jsonData, JsonRequestBehavior.AllowGet);
}
}
Is the JSON you are passing back to the grid valid? Are you passing back the information that the jqGrid needs? Why setup your jqGrid inside of an ajax call instead of inside your $(document).ready(function () { ?
Here is an example of the portion of code I use to format my json for jqGrid:
var jsonData = new
{
total = (totalRecords + rows - 1) / rows,
page = page,
records = totalRecords,
rows = (
from tempItem in pagedQuery
select new
{
cell = new string[] {
tempItem.value1,
tempItem.value2, ........
}
}).ToArray()
};
return Json(jsonData, JsonRequestBehavior.AllowGet);
If you want to make your user search first, you can on the client side, set the jqgrid datatype: local and leave out the url. Then after your user does whatever you want them to do you can have the jqGrid go out and fetch the data, via something like:
$('#gridName').jqGrid('setGridParam', { datatype: 'json', url: '/Controller/getGridDataAction' }).trigger('reloadGrid', [{ page: 1}]);
If you want to pass in the search data, or other values to the controller/action that is providing the data to the jqGrid you can pass it via the postData: option in the jqGrid. To set that before going out you can set it via the setGridParam option as shown above via postData: { keyName: pairData}.
MVC and jqGrid work great...there are a ton of examples on stackoverflow and Oleg's answers are a vast resource on exactly what you are trying to do. No hole in desk via head banging required!