Knockout.js - Reload a dropdown with new options using the value of another drop down - mvvm

I've seen similar things, where people have wanted to do this in ASP .NET, generic JavaScript, PHP, etc., but now here we have KnockOut that throws a wrench in things, since its fields are already rendered dynamically. Now here I go wanting to rewrite a dropdown when another is changed... dynamic loading on top of dynamic loading, all in old-fashioned cascading style....
I have a dropdown, "ourTypes", I've called it, that when changed, should re-write the options of the "slots" dropdown to its left. I have a .subscribe() function that creates new options based on a limit I get from the "ourTypes" value. All well and good, but how do we make the dropdown actually reflect those new values?
HTML:
<select data-bind="options: $root.slots, optionsValue: 'Value', optionsText: 'Text', value: $data.SlotPosition"></select>
<select data-bind="options: $root.ourTypes, optionsValue: 'ID', optionsText: 'Name', value: $data.OurTypeId"></select>
JavaScript:
var slots = [
{ Text: "1", Value: "1" },
{ Text: "2", Value: "2" },
{ Text: "3", Value: "3" }
];
var ourTypes = [
{ ID:"1", Name:"None", Limit:0 },
{ ID:"2", Name:"Fruits", Limit:5 },
{ ID:"3", Name:"Vegetables", Limit:5 },
{ ID:"4", Name:"Meats", Limit:2 }
];
var dataList = [
{ SlotPosition: "1", OurTypeId: 4 },
{ SlotPosition: "2", OurTypeId: 2 },
{ SlotPosition: "3", OurTypeId: 3 }
];
var myViewModel = new MyViewModel(dataList);
ko.applyBindings(myViewModel);
function MyViewModel(dataList) {
var self = this;
self.slots = slots;
self.ourTypes = ourTypes;
self.OurTypeId = ko.observable(dataList.OurTypeId);
self.SlotPosition = ko.observable(dataList.SlotPosition);
self.OurTypeId.subscribe(function() {
if (!ko.isObservable(self.SlotPosition))
self.SlotPosition = ko.observable("1");
// Get our new limit based on value
var limit = ko.utils.arrayFirst(ourTypes, function(type) {
return type.ID == self.OurTypeId();
}).Limit;
// Build options here
self.slots.length = 0;
self.slots.push({Text:"",Value:""});
for (var i=1; i < limit+1; i++) {
self.slots.push({Text:i, Value:i});
}
// What else do I do here to make the dropdown refresh
// with the new values?
});
}
Fiddle: http://jsfiddle.net/navyjax2/Lspwc4n4/

Well just made small changes in you code
View Model:
self.slots = ko.observableArray(slots); //should make it observable
self.ourTypes = ko.observableArray(ourTypes);
self.OurTypeId = ko.observable(dataList[0].OurTypeId); // initial value setting
self.SlotPosition = ko.observable(dataList.SlotPosition);
//Inside subscribe
self.slots([]); // clearing before filling new values
Working fiddle here

Related

Vuetify TreeView + Drag and drop

I am trying to implement drag and drop on Vuetify Treeview and data table. It seems like it is not supported fully but a workaround is described in this thread. The workaround is however not complete. Perhaps the community would benefit if someone created a codepen or similar on this?
What confuses me is that the component DragDropSlot.vue is created but "drag-drop-slot" is used in the code. Also there is a "_.cloneDeep(this.tree)" call where _ is not defined. I assume it should be replaced by something. When I comment that out drag and drop does still not work. Probably missed something more like defining data. Not sure of correct data types. It seems to be based on react which I have not worked with. Have just started to learn vue and vuetify.
I'm open for any suggestion for how to solve this.
All the best
I use V-Treeview with Vue.Draggable (https://github.com/SortableJS/Vue.Draggable).
I use direct link.
<script src="//cdn.jsdelivr.net/npm/sortablejs#1.8.4/Sortable.min.js"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/2.20.0 vuedraggable.umd.min.js"/>
<v-treeview
:active.sync="active"
:items="users"
:search="search"
item-key="Id"
item-text="UserName"
item-children="Children"
:open.sync="open"
activatable
color="warning"
dense
transition
return-object
>
<template v-slot:label="{ item }">
<draggable :list="users" group="node" :id="item.Id" :data-parent="item.ParentId" #start="checkStart" #end="checkEnd" >
<label>
<i class="fas fa-user mr-3" />
<span id="item.id" >{{item.UserName}}</span>
</label>
</draggable>
Also I add ParentId property to item tree model:
{
Id:1,
UserName: "John Doe",
ParentId: null,
Children:[{Id:2, ParentId: 1,...}]
}
Then I use start and end events where I search parent start node from I drag the item and parent end node where I drop the item. When parent is null the item is a root.
new Vue({
el: '#app',
vuetify: new Vuetify(),
components: {
vuedraggable
},
data() {
return {
active: [],
open: [],
users: [],
selectedItems: [],
}
},
mounted: function () {
this.fetchUsers();
},
methods: {
findTreeItem: function (items, id) {
if (!items) {
return;
}
for (var i = 0; i < items.length; i++) {
var item = items[i];
// Test current object
if (item.Id === id) {
return item;
}
// Test children recursively
const child = this.findTreeItem(item.Children, id);
if (child) {
return child;
}
}
},
checkStart: function (evt) {
var self = this;
self.active = [];
self.active.push(self.findTreeItem(self.users, evt.from.id))
},
checkEnd: function (evt) {
var self = this;
var itemSelected = self.active[0];
var fromParent = itemSelected.ParentId ? self.findTreeItem(self.users, itemSelected.ParentId) : null;
var toParent = self.findTreeItem(self.users, evt.to.id);
var objFrom = fromParent ? fromParent.Children : self.users;
objFrom.splice(objFrom.indexOf(itemSelected), 1);
if (toParent.Id === itemSelected.Id) {
itemSelected.ParentId = null;
self.users.push(itemSelected);
}
else {
itemSelected.ParentId = toParent.Id;
toParent.Children.push(itemSelected);
}
self.saveUser(itemSelected);
// self.active = [];
return false;
},
fetchUsers: function () {
//load from api
},
saveUser: function (user) {
//save
},
},
computed: {
selected() {
if (!this.active.length) return undefined
return this.active[0];
},
}
})
Hope I help you.
IngD.
After some additional work I ended up with implementing Drag and Drop on top of vuetify tree view and data table using this library:
https://www.vuetoolbox.com/projects/vue-drag-drop
At first I looked at draggable and similar but realized it was always based on that you move an element from position A to position B. I needed more control. For example I wanted the element to disappear when dropping on some drop zones.
found this component.
https://vuejsexamples.com/vuetify-draggable-v-treeview-component/
I didn't try it myself (because it has too few options), but it looks working well in demo.
Anyways, just to try

REACT.js on select disable radio button and check second option

I have been changing a form based on REACT and this is something I am a newb with (been using it already for 4 months but just segments of it, sometimes actual progress with the programming is based on pure luck and every time on advices of good people found here).
Currently I have a task of re-developing a form of this look:
What I need to achieve is Calibration radios' behavior based on Type's selection: if argument calibration is set to 0 (zero) then disable option 'Accredited' and check second option automatically.
Edited: 19 Oct 2017
This creates the drop down, and the DD works great:
createSuggestInput(name) {
const { id, value, labels } = this.props;
const _t = this.props.intl.formatMessage;
var options = [
{ value: 'one', label: 'One', calibration: '0' },
{ value: 'two', label: 'Two ', calibration: '1' },
{ value: 'three', label: 'Three', calibration: '0' },
{ value: 'four', label: 'Four', calibration: '1' },
];
return <Select.Creatable
name = {`${id}_${name}`}
value = {this.state.brandSelect}
placeholder = {_t(translations.txtSuggest)}
options = {options}
onChange = {this._onChange.bind(this)}
label = {labels[name]}
key = {`${id}_${name}`}
promptTextCreator = { (label) => _t(translations.txtCreate) + ' ' + label + _t(translations.txtCreateEnter) }
/>;
}
When selected option's calibration value is ZERO, I need to update set of Calibration radio buttons, by disabling the option "Accredited" and at the same time checking the second option, "Not Accredited".
createRadioCalibration(name) {
const { id, value, labels } = this.props;
const _t = this.props.intl.formatMessage;
const ACCREDITATION_TYPES = [
[CALIBRATION_ACCREDITED, _t(messages.calibrationAccredited)],
[CALIBRATION_NOT_ACCREDITED, _t(messages.calibrationNotAccredited)]
];
return <FormChoiceGroup
type = "radio"
values = {ACCREDITATION_TYPES.map(mapValueArray)}
key = {`${id}_${name}`}
name = {`${id}_${name}`}
value = {value[name]}
handleChange = {this.handleFieldChangeFn(name)}
/>;
}
These two are rendered as follows:
render () {
const FIELDS = {
[CALIBRATION]: this.createRadioCalibration(CALIBRATION),
[TYPE]: this.createSuggestInput(TYPE),
};
return (
<div className="repair-form-device repair-form-device-field-row">
<div className="repair-form-device-id">
{id + 1}
</div>
<div className="clearfix repair-form-device-content">
<div className="">
{ FIELDS[TYPE] }
</div>
<div className="">
<label>{_t(messages.repair)}</label>
{ FIELDS[CALIBRATION] }
</div>
.....
And lastly the _onChange function:
_onChange(tool) {
const { id } = this.props;
this.setState({
brandSelect: tool
});
}
As I stated previously, I am stuck with the main task, which is manipulating the Calibration radio buttons.
I believe I can update its status inside the _onChange function, but everything I tested so far lead me nowhere.
Your patience is much appreciated!

How to connect to SharePoint Online with IP address

I would like to know how to successfully connect to spo service url with a IP address.
Connect-SPOService https://13.xxx.xxx.9-admin.sharepoint.com
How about triggering the Excel export manually on button click using kendo.ooxml.Workbook combined with kendo.saveAs?
I have made up a Kendo Dojo example. Let me know if this is what you need. Additionally, if you need to retrieve the name of your screen, there are some examples of how to do this here
EDIT
Below is an example of the export generated by the Dojo example when the "Click to Export" button is pressed. Note that the title is custom.
Not sure why this would not work for you, but try the following example with your code and see what happens. Basically, you can hook up the custom function to handle the export button click as follows:
$("#exportButton").kendoButton({
click: function () {
var grid = $("#yourGrid").getKendoGrid();
// declare `rows` and supply your own column names
var rows = [{
cells: [
{ value: "ContactTitle" },
{ value: "CompanyName" },
{ value: "Country" }
]
}];
var trs = grid.dataSource;
// will get any filters applied to grid dataSource
var filteredDataSource = new kendo.data.DataSource({
data: trs.data(),
filter: trs.filter()
});
filteredDataSource.read();
var data = filteredDataSource.view();
for (var i = 0; i < data.length; i++) {
var dataItem = data[i];
rows.push({
cells: [ // dataItem."Whatever Your Attributes Are"
{ value: dataItem.ContactTitle },
{ value: dataItem.CompanyName },
{ value: dataItem.Country }
]
});
}
excelExport(rows);
}
});
This sets up the rows to be exported, and the excelExport function carries out the export:
function excelExport(rows) {
var workbook = new kendo.ooxml.Workbook({
sheets: [
{
columns: [
{ autoWidth: true },
{ autoWidth: true }
],
title: "Name of Tab",
rows: rows
}
]
});
var nameOfPage = "Test-1"; // insert here however you are getting name of screen
kendo.saveAs({ dataURI: workbook.toDataURL(), fileName: nameOfPage + " Export.xlsx" });
}
Let me know the outcome.

How to apply CSS to sap.m.table row based on the data in one of the cell in that row

I am working with sap.m.table. I have requirement to apply or change the background color for some of the rows based on the data in one of the column in those rows in table.
I am using the following code but it is not working
created the CSSfile: test.css
<style type="text/css">
.Total {
background-color: LightSteelBlue !important;
}
</style>
The above CSS file declare in Component.js like the following way ( correct me if this not right way to make the css file available to access in whole ui5 project.
"resources": {
"css": [
{
"uri": "css/test.css"
}
]
}
In Controller.i have defined the following method to apply the style sheet for the particular rows alone in table.
rowColours: function() {
var oController = this;
console.log("rowColours() --> Start ");
var oTable = this.oView.byId("tblAllocation");
var rows = oTable.getItems().length; //number of rows on tab
//start index
var row;
var cells = [];
var oCell = null;
for (i = 0; i < oTable.getItems().length; i++) {
//console.log("rowColours() :: row--> "+row);
//actualRow = oTable.getItems(); //content
if (i == 0) {
row = oTable.getItems()[i];
cells = cells.concat(oTable.getItems()[i].getCells());
//getting the cell id
oCell = cells[2];
oCell = oCell.toString().substring(29, oCell.length);
otemp = this.getView().byId(oCell).getText();
if (otemp.toString() == "TotalAllocation") {
oTable.getItems()[i].$().taggleClass("grandTotal");
}
}
}
console.log("rowColours() --> end ");
}
In the above method. I am checking the cell2 data ( in table cell 2 i was using the Textview control to display the data. when call this method to get the data in that cell. I am getting the following error.
otemp = this.getView().byId(oCell).getText());
error:
Uncaught TypeError: Cannot read property 'getText' of undefined
is the following code is possible to change the row bg color.
if (otemp.toString() == "TotalAllocation") {
oTable.getItems()[i].$().taggleClass("Total");
}
Please let me know how to change the bg color or applying the style for the perticular row in sap.m.table
Thanks
The approach your following is not right. Better you can use a formatter.
Example:
var oTable = new sap.m.Table({
columns: [
new sap.m.Column({
header: new sap.m.Label({
text: "Name"
}),
}),
],
items: {
path: 'modelList>/',
template: new sap.m.ColumnListItem({
cells: [
new sap.m.Text({
//formatter to the text property on sap.m.Text control.
text: {
parts: [{
"path": "modelList>Name"
}],
formatter: function(name) {
if (name == "TotalAllocation") {
// use this.getParent().. until u get the row. like this below and add class.
this.getParent().getParent().addStyleClass("Total");
}
}
}
})
]
})
}
});

sapui5 :- text not shown on ui5 in Dropdown Box

The values are loaded from the data source but on ui no text is shown.
var r0c1 = new sap.ui.commons.DropdownBox("r0c1");
var oItemTemplate1 = new sap.ui.core.ListItem();
property binding is done:
oItemTemplate1.bindProperty("text", "{ZtmDockid}");
bind the items:
r0c1.bindItems("/d/results", oItemTemplate1);
Data is properly coming, but on UI its not showing the text.
there are two ways to bind data to a control.
First way using bindProperty:
var oItemTemplate1 = new sap.ui.core.ListItem();
oItemTemplate1.bindProperty("text", "value");
(notice: usage of { })
or binding the values when creating the control:
var oItemTemplate1 = new sap.ui.core.ListItem({
text: "{value}"
});
(you need to use { } to indicate dynamic values)
Herrlock is correct, but I wanted to draw out the subtlety - explicit binding with the bind* functions requires no curly braces ... these are only needed for embedded, or implicit binding.
Here's your code with the braces removed from your bindProperty's second parameter, as a runnable snippet.
// Code from question
var r0c1 = new sap.ui.commons.DropdownBox("r0c1");
var oItemTemplate1 = new sap.ui.core.ListItem();
oItemTemplate1.bindProperty("text", "ZtmDockid");
r0c1.bindItems("/d/results", oItemTemplate1);
// Extra code
r0c1
.setModel(new sap.ui.model.json.JSONModel({
d : {
results : [
{ ZtmDockid : "1" },
{ ZtmDockid : "2" },
{ ZtmDockid : "3" }
]
}
}))
.placeAt('content');
<script src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-libs="sap.m,sap.ui.commons"
data-sap-ui-theme="sap_bluecrystal"></script>
<div id="content"></div>