Saving changes in SlickGrid - javascript

HI,
I'm looking at SlickGrid and I can see example on how to edit the cell, however do I save these changes. I have yet to find an example that tells me how to do this.

The trick to saving the SlickGrid is to realise that the grid will update the array of data that you supplied when creating the grid as the cells are edited.
The way I then save that is to include a form with a submit button and a hidden field below the grid. I trap the submit event and use the JSON plugin to serialise the array and place it in the hidden field. On the server side you'll receive a JSON string which you can deserialise, loop through and write to the database.
Assuming your array of data is called "data" like the samples, the following should work for you:
<form action="?" method="POST">
<input type="submit" value="Save">
<input type="hidden" name="data" value="">
</form>
<script>
$(function() {
$("form").submit(
function() {
$("input[name='data']").val($.JSON.encode(data));
}
);
});
</script>

For completeness, a minimal example demonstrating the usage of onCellChange, referred to in Jim OHalloran's post.
For more information, and to see all events that can be utilized similarly to onCellChange, see comments at the beginning of the SlickGrid source.
<head>
<!-- boilerplate omitted ... -->
<script type="text/javascript">
var grid;
var options = {
enableCellNavigation: true,
enableColumnReorder: false,
autoEdit: false,
editable: true,
};
var columns = [
{id: "item_key", name: "Key", field: "item_key" },
{id: "value", name: "value", field: "value", editor: LongTextCellEditor }
];
var data = [
{item_key: "item1", value: "val1"},
{item_key: "item2", value: "val2"},
];
$(document).ready(function () {
grid = new Slick.Grid($("#myGrid"), data, columns, options);
//Earlier code for earlier version of slickgrid
// grid.onCellChange = function (currentRow, currentCell, item) {
// alert(currentRow+":"+currentCell+"> key="+item['item_key']+", value="+item['value']);
//Updated code as per comment.
grid.onCellChange.subscribe(function (e,args) {
console.log(args);
});
};
});
</script>
</head>
<body>
<div id="myGrid" style="height:10em;"> </div>
</body>

While I'm personally using the JSON serialize and submit in a hidden field approach from my previous answer another approach could be to trap the onCellChange event fired by SlickGrid after a cell value has changed and make an Ajax call to the server to save the changed value. This will result in lots of small Ajax requests to the server (which may increase load) but updates the server as soon as changes are made.

Related

How add new values in drop-down list using plugin "selectory" jquery

I need some help. How can I add new values in code to the list if I use a plugin from jquery. I wrote this code, but the list is empty, although the values are passed to the view. This is probably due to the fact that I am referring to the id of the div tag, but the plugin did not work differently. Help please
<html>
<main>
<form action="#">
<div class="form-group col-xs-12 col-sm-4" id="example-2"> </div>
</form>
</main>
<script>
$('#example-2').selectivity({
items: ['Amsterdam', 'Antwerp'],
multiple: true,
placeholder: 'Type to search a city'
});
function addOption() {
var ul = document.getElementById("#example-2");
for (var item in #ViewBag.List)
{
var value = item;
}
var newOption = new Option(value, value);
ul.options[ul.options.length] = newOption;
}
</script>
</html>
result of code from answer 1
The documentation of the selectivity library covers how to add new options to the dropdown.
The main issue you have is that the output from #ViewBag.List won't be in a format that JS can understand. I would suggest formatting it as JSON before outputting it to the page, then the JS can access this as a standard object, though which you can loop.
// initialisation
$('#example-2').selectivity({
items: ['Amsterdam', 'Antwerp'],
multiple: true,
placeholder: 'Type to search a city'
});
// add options, somewhere else in your codebase...
const $list = $('#example-2')
const options = #Html.Raw(Json.Encode(ViewBag.List));
options.forEach((option, i) => {
$list.selectivity('add', { id: i, text: option })
});
Note that for this to work the JS code which reads from the ViewBag needs to be placed somewhere the C# code will be executed, ie. in a .cshtml file, not in a .js file.

Group results in autocompleted dropdown [Meteor]

I try to do a dropdown list in my app. First of all I use a Meteor, so that's specific kind of app ofc :)
Second thing is that I use sebdah/meteor-autocompletion package, because I want my results to be sorted in specific way and limited.
The last thing I need is to group my results.
For example: If I have 2 products named "blah" I want to get only 1 "blag" in my dropdown "autocompletion" list.
Some code:
HTML:
<template name="InvoicesEditInsertInsertForm">
<input id="descriptionautocomplete" type="text" name="description" value="" class="form-control" autofocus="autofocus" placeholder="New Item...">
</template>
JS:
Template.InvoicesEditInsertInsertForm.rendered = function() {
AutoCompletion.init("input#descriptionautocomplete");
};
Template.InvoicesEditInsertInsertForm.events({
'keyup input#descriptionautocomplete': function () {
AutoCompletion.autocomplete({
element: 'input#descriptionautocomplete', // DOM identifier for the element
collection: InvoicesItem, // MeteorJS collection object
field: 'description', // Document field name to search for
limit: 5, // Max number of elements to show
sort: { modifiedAt: -1 },
}); // Sort object to filter results with
},
});
I need to use function that could group my "description" here.
I tried to do it in helper and I get it on my screen, but to be honest I don't know how to put that into my dropdown :(
try: function() {
var item= InvoicesItem.find({},{sort:{modifiedAt:-1}}).fetch();
var descriptions={};
_.each(item,function(row){
var description = row.description;
if(descriptions[description]==null)
descriptions[description]={description:description};
});
return _.values(descriptions);
},
I don't think you can do what you want with that package. If you have a look at the current limitations of the package documentation, you can see other potential solutions to your problem.
You can do addtional filtering as follows:
filter: { 'gender': 'female' }});
but I don't think this will allow you to demand only unique options.
The code you wrote above for try won't do anything. Autocomplete doesn't take a field called try.

Ractive, two bindings on an <input>

Note: I'm not referring to "two way binding"
I'm using a ractive decorator (select2) to transform an input into a select2. The data I obtain through ajax are some records from the database, example:
[{id:1, name:"test", quantity:2, image:"image.jpg"},
{id:2, name:"bar", quantity:21, image:"image2.jpg"},
{id:3, name:"foo", quantity:21, image:"image3.jpg"}]
I format these object using select2's functions, formatResult and formatSelection
The element on which I'm using the decorator is something like this:
<input type="hidden" value="{{values}}" decorator="select2">
After the user select something, values will be equal to the ids of the selected object, (eg: values=1,3 if i select the first and the last records)
My question is: how can i obtain the full object that was selected? I was thinking about two bindings on the <input> (<input value="{{values}}" data-objects="{{objects}}"> so the decorator can save the full objects too, when the user select something. But when i debug the decorator, node._ractive.binding only shows value and not other attributes.
I solved it by saving the result of the ajax request in ractive, then matching the ids with the object ids to find the original objects.
Not the prettiest thing, but it works.
Ractive.decorators.select2.type.whatever = {
tags: [],
separator: "|",
ajax: {
url: "ajax_url",
data: function(searchterm, page) {
return {
searchterm: searchterm,
page: page,
};
},
results: function(data, page) {
//Here i save the records
ractive.set("data", data.records);
return {results: data.records, more: data.more};
}
}
};
var ractive = new Ractive({
el: "things",
template: "template",
});
ractive.observe("ids", function(ids) {
var data = ractive.get("data");
ids = ids.split("|");
//I can obtain the original objects
});
<script src="http://cdn.ractivejs.org/latest/ractive.js"></script>
<script src="https://rawgit.com/Prezent/ractive-decorators-select2/master/ractive-decorators-select2.js"></script>
<!-- select2, jquery missing -->
<script type="ractive-template" id="template">
<input type="hidden" value="{{ids}}" decorator="select:whatever">
</script>
<div id="things"></div>

creating a dynamic form that builds a multi dimensional array

I am a php developer that is new to angular and javascript in general but finding it really powerful and fast for creating interactive UIs
I want to create a form for a user to create an object called a program, a program has some basic info like title and description and it can have many weeks. I want their to be an 'add week' button that when pressed displays a group of form fields related to weeks, if pushed again it shows another group of form fields to fill in the second weeks information.
edit1: specifically, how I am adding the objects to scope.program with the addWeeks method.
secondly when I console.log the $scope.program it just looks very messy a lot of arrays within objects within objects. it just dosnt look like a clean array of data but maybe thats just because I am not used to javascript and or json? Each week is going to have up to 7 days obviously and each day can have numerous events so it just seems to me like it is going to be quite messy but maybe I should just have faith :p
finally how the addProgram method is creating the json object to be sent to the server
when the form is submitted it should post a json object that looks something like this
program {
title: 'name of programme',
desc: 'description of programme',
weeks: [
{
item1: 'foo',
item2: 'more foo'
},
{
item1: 'foo2',
item2: 'more foo 2'
}
]
]
}
here is a codepen of what I am doing right now but I am not sure it is the best or even an ok way to do it, particularly how I am appending the arrays/objects in teh addWeek method.
there are going to be many more layers to the form and the object it is posting(days, sessions, excersises etc) so I want to get the basics of doing this right before adding all of that.
html
<div ng-app="trainercompare">
<div ng-controller="programsController">
<input type="text" placeholder="Program Title" ng-model="program.title"></br>
<input type="text" placeholder="Program Focus" ng-model="program.focus"></br>
<input type="text" placeholder="Program Description" ng-model="program.desc"></br>
<button ng-click="addWeek()"> add week</button>
<div ng-repeat="week in program.weeks">
<input type="text" placeholder="Name the week" ng-model="week.name">
<input type="text" placeholder="Describe It" ng-model="week.desc">
{{ week.name }}</br>
{{ week.desc }}</br>
</div>
<button ng-click="addProgram()"> add program</button>
</div>
</div>
app.js
var myModule = angular.module("trainercompare", ['ui.bootstrap']);
function programsController($scope, $http) {
$scope.program = {
weeks: [{
}]
};
$scope.addWeek = function() {
$scope.program.weeks.push(
{
}
);
};
function isDefined(x) {
var undefined;
return x !== undefined;
}
$scope.addProgram = function() {
var program = {
title: $scope.program.title,
focus: $scope.program.focus,
desc: $scope.program.desc,
weeks: []
};
angular.forEach($scope.program.weeks, function(week, index){
var weekinfo = {
name: week.name,
desc: week.desc
};
program.weeks.push(weekinfo);
});
$http.post('/programs', program).success(function(data, status) {
if(isDefined(data.errors)) {
console.log(data.errors);
}
if(isDefined(data.success)) {
console.log(data.success);
}
});
};
}
Looks to me like you've got a good grasp on it. The addWeek code looks correct. The extra data you see when you console.log your model is some of Angular's internal stuff to track bindings. When you post that to your server it should be cleaned up by Angular.
Angular has a JSON function that removes all of the hash values and other 'angular' things from your JSON. That's why they start with a $ so it knows to remove them.
This happens automatically when you use $http, it's in the documentation here:
If the data property of the request configuration object contains an object, serialize it into JSON format.
Since Angular will clean up the hashes and things, you don't need to "rebuild" the model when you're posting it... just set data to $scope.program and remove 70% of the code in $scope.addProgram.
To learn more specifically how Angular cleans up the JSON, look at this answer: Quick Way to "Un-Angularize" a JS Object

How can I remove AutoNumeric formatting before submitting form?

I'm using the jQuery plugin AutoNumeric but when I submit a form, I can't remove the formatting on the fields before POST.
I tried to use $('input').autonumeric('destroy') (and other methods) but it leaves the formatting on the text fields.
How can I POST the unformatted data to the server? How can I remove the formatting? Is there an attribute for it in the initial config, or somewhere else?
I don't want to send the serialized form data to the server (with AJAX). I want to submit the form with the unformatted data like a normal HTML action.
I wrote a better, somewhat more general hack for this in jQuery
$('form').submit(function(){
var form = $(this);
$('input').each(function(i){
var self = $(this);
try{
var v = self.autoNumeric('get');
self.autoNumeric('destroy');
self.val(v);
}catch(err){
console.log("Not an autonumeric field: " + self.attr("name"));
}
});
return true;
});
This code cleans form w/ error handling on not autoNumeric values.
With newer versions you can use the option:
unformatOnSubmit: true
Inside data callback you must call getString method like below:
$("#form").autosave({
callbacks: {
data: function (options, $inputs, formData) {
return $("#form").autoNumeric("getString");
},
trigger: {
method: "interval",
options: {
interval: 300000
}
},
save: {
method: "ajax",
options: {
type: "POST",
url: '/Action',
success: function (data) {
}
}
}
}
});
Use the get method.
'get' | returns un-formatted object via ".val()" or
".text()" | $(selector).autoNumeric('get');
<script type="text/javascript">
function clean(form) {
form["my_field"].value = "15";
}
</script>
<form method="post" action="submit.php" onsubmit="clean(this)">
<input type="text" name="my_field">
</form>
This will always submit "15". Now get creative :)
Mirrored raw value:
<form method="post" action="submit.php">
<input type="text" name="my_field_formatted" id="my_field_formatted">
<input type="hidden" name="my_field" id="my_field_raw">
</form>
<script type="text/javascript">
$("#my_field_formatted").change(function () {
$("#my_field").val($("#my_field_formatted").autoNumeric("get"));
});
</script>
The in submit.php ignore the value for my_field_formatted and use my_field instead.
You can always use php str_replace function
str_repalce(',','',$stringYouWantToFix);
it will remove all commas. you can cast the value to integer if necessary.
$("input.classname").autoNumeric('init',{your_options});
$('form').submit(function(){
var form=$(this);
$('form').find('input.classname').each(function(){
var self=$(this);
var v = self.autoNumeric('get');
// self.autoNumeric('destroy');
self.val(v);
});
});
classname is your input class that will init as autoNumeric
Sorry for bad English ^_^
There is another solution for integration which doesn't interfere with your client-side validation nor causes the flash of unformatted text before submission:
var input = $(selector);
var proxy = document.createElement('input');
proxy.type = 'text';
input.parent().prepend(proxy);
proxy = $(proxy);
proxy.autoNumeric('init', options);
proxy.autoNumeric('set', input.val())''
proxy.change(function () {
input.val(proxy.autoNumeric('get'));
});
You could use the getArray method (http://www.decorplanit.com/plugin/#getArrayAnchor).
$.post("myScript.php", $('#mainFormData').autoNumeric('getArray'));
I came up with this, seems like the cleanest way.
I know it's a pretty old thread but it's the first Google match, so i'll leave it here for future
$('form').on('submit', function(){
$('.curr').each(function(){
$(this).autoNumeric('update', {aSign: '', aDec: '.', aSep: ''});;
});
});
Solution for AJAX Use Case
I believe this is better answer among all of those mentioned above, as the person who wrote the question is doing AJAX. So
kindly upvote it, so that people find it easily. For non-ajax form submission, answer given by #jpaoletti is the right one.
// Get a reference to any one of the AutoNumeric element on the form to be submitted
var element = AutoNumeric.getAutoNumericElement('#modifyQuantity');
// Unformat ALL elements belonging to the form that includes above element
// Note: Do not perform following in AJAX beforeSend event, it will not work
element.formUnformat();
$.ajax({
url: "<url>",
data : {
ids : ids,
orderType : $('#modifyOrderType').val(),
// Directly use val() for all AutoNumeric fields (they will be unformatted now)
quantity : $('#modifyQuantity').val(),
price : $('#modifyPrice').val(),
triggerPrice : $('#modifyTriggerPrice').val()
}
})
.always(function( ) {
// When AJAX is finished, re-apply formatting
element.formReformat();
});
autoNumeric("getArray") no longer works.
unformatOnSubmit: true does not seem to work when form is submitted with Ajax using serializeArray().
Instead use formArrayFormatted to get the equivalent serialised data of form.serializeArray()
Just get any AutoNumeric initialised element from the form and call the method. It will serialise the entire form including non-autonumeric inputs.
$.ajax({
type: "POST",
url: url,
data: AutoNumeric.getAutoNumericElement("#anyElement").formArrayFormatted(),
)};

Categories