I have a dynamic form:
var Form = React.createClass({
log: function(e) {
console.log(e.target.value);
},
getInitialState: function () {
return {counter: 2};
},
handleChange : function(e) {
this.setState({counter: parseInt(e.target.value)});
},
render: function () {
var fields = [
React.createElement('input', {key: -2, onChange: this.handleChange}),
React.createElement('input', {key: -1, onChange: this.log})
];
for (var x = 0; x < this.state.counter; x++) {
fields.push(React.createElement('input', {key: x, onChange: this.log}));
}
return React.createElement('div', {}, fields);
}
});
The form is in a separate node module and I require it as:
var Form = require('custom-forms');
In the first input field I control the number of input fields. The log method of the newly created input fields is never invoked. There are no listeners for the new input fields.
When I move the form in the main project, everything is ok. The values are logged on the console when there is a change in the input.
Does anyone know where the problem could come from?
Related
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
I am using ASP MVC and I have a ej chart built in script, and I need to refresh its content:
my chart is built like this:
var modelSummaryList = getMySummaryModel();
var summaryChartDataManager = ej.DataManager(($scope.FirstLoad && IsCurrentUserDpiUser()) ? null : modelSummaryList);
jQuery("#MySummaryChart").ejChart({
range: { min: summaryChartDataManager == null ? -1 : summaryChartDataManager.ChartMin, max: summaryChartDataManager == null ? 1 : summaryChartDataManager.ChartMax },
series: [{
name: "MTM",
tooltip: {
visible: true,
format: "#point.x#: #point.y# #series.name#"
},
dataSource: summaryChartDataManager,
xName: "CtpyShort",
yName: "MTM"
}, {
name: "Threshold",
tooltip: {
visible: true,
format: "#point.x#: #point.y# #series.name#"
},
dataSource: summaryChartDataManager,
xName: "CtpyShort",
yName: "Threshold"
}, {
name: "My Held/(Posted)",
tooltip: {
visible: true,
format: "#point.x#: #point.y# #series.name#"
},
dataSource: summaryChartDataManager,
xName: "CtpyShort",
yName: "Held"
}],
type: 'column',
});
which is working good, but upon filter and change of data, I need to redraw the chart so I did this:
$scope.RefreshChart = function (data) {
var chart = $("#MySummaryChart").ejChart("instance");
chart.model.range.min = data.MyTradeSummaryVM.ChartMin;
chart.model.range.max = data.MyTradeSummaryVM.ChartMax;
for (var s = 0; s <= chart.model.series.length - 1; s++) {
var pts = IsCurrentUserDpiUser() ? $.grep(data.MyTradeSummaryVM, function (item) {
return item.ClientID == localStorage.getItem("MyPosting_client_sticky");
}) : data.MyTradeSummaryVM;
chart.model.series[s].points = [];
for (var p = 0; p <= pts.length - 1; p++) {
var newPt = new Object();
newPt.x = pts[p].CtpyShort;
if (chart.model.series[s].name == "MTM")
newPt.y = pts[p].MTM;
else if (chart.model.series[s].name == "Threshold")
newPt.y = pts[p].Threshold;
else if (chart.model.series[s].name == "My Held/(Posted)")
newPt.y = pts[p].Held;
newPt.visible = true;
chart.model.series[s].points.push(newPt);
}
}
chart.redraw();
};
which throws the error TypeError: n[0] is undefined on the chart.redraw() line, and I am stumped. Please note that the RefreshChart() works if I build the chart via cshtml and not javascript like this:
#(Html.EJ().Chart("MySummaryChart")
.PrimaryXAxis(pr => pr.Title(tl => tl.Text("")))
.PrimaryYAxis(pr => pr.Range(ra => ra.Max(Model.ChartMax).Min(Model.ChartMin)).Title(tl => tl.Text("")))
.CommonSeriesOptions(cr => cr.Type(SeriesType.Column).EnableAnimation(true).Marker(mr => mr.DataLabel(dt => dt.Visible(true).EnableContrastColor(true)))
.Tooltip(tt => tt.Visible(true).Format("#point.x# : #point.y# #series.name# ")))
.Series(sr =>
{
.
.
.
})
.Load("loadTheme")
.IsResponsive(true)
.Size(sz => sz.Height("400"))
.Legend(lg => { lg.Visible(true).Position(LegendPosition.Bottom); }))
but I am opting to use JS coz I need to handle null and firstload(meaning no data should appear on the chart upon first load, and unless user picks a client(filter), no data should be loaded. Which I cant seem to make it work if via html, I couldn't erase the chart xaxisregions label along with other data, the only things erased are the main Y axis points but not labels.
We have analyzed the reported scenario. We would like to you know that, when the data for chart is bind using dataSource, then while refreshing the chart with new data, you need to bind the data to series.dataSource property not to series.points, so that only chart will refresh properly. We have prepared a sample with respect the above scenario. Find the code snippet to achieve this requirement.
<input type="button" id="refreshChart" onclick="refresh()" value="Refresh Chart" />
function refresh(sender) {
var chart = $("#MySummaryChart").ejChart("instance");
for (var s = 0; s <= chart.model.series.length - 1; s++) {
//Obtained random data,
var pts = GetData().data;
var newPt = [];
for (var p = 0; p <= pts.length - 1; p++) {
if (chart.model.series[s].name == "MTM")
newPt.push({ "CtpyShort": pts[p].CtpyShort, "MTM": pts[p].MTM });
else if (chart.model.series[s].name == "Threshold")
newPt.push({ "CtpyShort": pts[p].CtpyShort, "Threshold": pts[p].Threshold });
else if (chart.model.series[s].name == "My Held/(Posted)")
newPt.push({ "CtpyShort": pts[p].CtpyShort, "Held": pts[p].Held });
}
//Assign the updated data to dataSource property
chart.model.series[s].dataSource = newPt;
}
chart.redraw();
}
In the above code in a button click event, we have refreshed the chart data. Here you need to assign the x value to CtpyShort and y values of three series to MTM, Threshold and Held, since we have mapped these properties while rendering the chart initially.
Screenshot before updating data:
Screenshot after updating data:
Sample for reference can be find from below link.
Sample Link
If you face still any concern, kindly revert us by modifying the above sample with respect to your scenario or provide your sample with replication steps which will helpful in further analysis and provide you the solution sooner.
Thanks,
Dharani.
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.
I need to create more forms on-the-fly. This example creates two forms dynamically, it works, but not in the events section.
<div id="form_container" style="width:280px;height:250px;"></div>
<script>
var array_form = array_grid = new Array();
formStructure_modBase = [
{type: "block", blockOffset: 0, list: [
{type:"input",label:"",name:"id_base"},
{type:"container",name:"grid_base",label:"",inputWidth:400,inputHeight:150},
{type:"button",name:"button_base",value:"SAVE"},
]},
];
for(var ii=0;ii<=1;ii++)
{
//create array form
array_form[ii] = new dhtmlXForm("form_container",formStructure_modBase);
array_form[ii].setItemValue("id_base",ii);
//events (DOESN'T WORK!)
array_form[ii].attachEvent("onButtonClick", function(id){
if(id=="button_base") alert("Save Form "+ii);
});
//create grid
array_grid[ii] = new dhtmlXGridObject(array_form[ii].getContainer("grid_base"));
array_grid[ii].setImagePath("../../codebase/imgs/");
array_grid[ii].setHeader("Num,Des");
array_grid[ii].setInitWidthsP("50,50");
array_grid[ii].setColAlign("center,left");
array_grid[ii].setColTypes("ro,ed");
array_grid[ii].setSkin("dhx_web");
array_grid[ii].init();
}
</script>
This code works properly, but the number of forms is not known at design time.
array_form[0].attachEvent("onButtonClick", function(id){
if(id=="button_base") alert("Save Form 0");
});
array_form[1].attachEvent("onButtonClick", function(id){
if(id=="button_base") alert("Save Form 1");
});
How can I handle events correctly?
Thanks.
UPDATE
This seems to work properly:
..
..
//create array form
array_form[ii] = new dhtmlXForm("form_container",formStructure_modBase);
array_form[ii].setItemValue("id_base",ii);
//events (WORKS)
addEvent(ii);
//create grid
array_grid[ii] = new dhtmlXGridObject(array_form[ii].getContainer("grid_base"));
..
..
function addEvent(form_num)
{
array_form[form_num].attachEvent("onButtonClick", function(id){
if(id=="button_base") alert("Save Form "+form_num);
});
}
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