I'm using SlickGrid (2.0) dataView with slick.editors. In the Grid, a user can edit any number of cells which then modifies the underlying grid data so that the edits are maintained when the grid scrolls. This works great. But I also want to provide visual feedback for all the edits since these are not saved to the database until user hit "Save Edits" button.
Problem is that the editor method resets the cell after it reads back the changed grid data. I need to maintain a background color change to indicate that it's been edited. Has anyone been able to do this?
Here is the relevent code (simple Integer editor):
function IntegerCellEditor(args) {
var $input;
var defaultValue;
var scope = this;
this.init = function() {
$input = $("<input type=text class='edited' type=text style='font:normal 12px arial; width:95px; text-align:right; border:none;' />");
$input.bind("keydown.nav", function(e) {
if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
e.stopImmediatePropagation();
}
});
$('#saveChanges').removeAttr("disabled"); // remove disabled attribute from "Save Changes" btn
$input.appendTo(args.container);
$input.focus().select();
};
this.destroy = function() {
$input.remove();
};
this.focus = function() {
$input.focus();
};
this.loadValue = function(item) {
defaultValue = item[args.column.field];
$input.val(defaultValue);
$input[0].defaultValue = defaultValue;
$input.select();
};
this.serializeValue = function() {
return parseInt($input.val(),10) || 0;
};
this.applyValue = function(item,state) {
item[args.column.field] = state;
};
this.isValueChanged = function() {
return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
document.getElementsByClassName('ui-widget-content slick-row')[row].className += 'edited';
};
this.validate = function() {
if (isNaN($input.val()))
return {
valid: false,
msg: "Please enter a valid integer"
};
return {
valid: true,
msg: null
};
};
this.init();
}
This line does nothing and I can't figure out how to do this:
document.getElementsByClassName('ui-widget-content slick-row')[row].className += 'edited';
Thanks
I am not an expert in SlickGrid but take a look a Example 14, I think it has similar information that would help you.
My idea would be something like:
subscribe to grid.onCellChange event
store changes in object
use grid.setCellCssStyles('highlight',changes) to update CSS or grid.addCellCssStyles
Hope that helps a little at least.
Related
I am trying to refresh a bootstrap 3.0 multiselect control.
On refresh, I want to reset the checkboxes to its previous state when the partial view was first rendered
How can I achieve that?
I tried following approach but didn't get success.
Maintained hidden field for storing selected checkbox values once view
was rendered.
On Reset button click:
2.1 Uncheck all checkboxes.
2.2 Check only those checkboxes whose value I got from hidden field.
j('#btnReset11').click(function () {
j("#divErrorMessage ul li").not(':first').remove();
j("#divErrorMessage").hide();
j("#divSuccessMessage").hide();
j("#includeSelectAllOption").find("option").removeAttr("selected");
j("#chkRoles ul li").removeClass("active");
j("#chkRoles .btn-group").find("button").removeAttr('title');
j("#chkRoles .btn-group").find("button").text('Select');
var value = j("#selectedCheckboxes").val();
valueItems = value.split(", ");
for (var i = 0; i < valueItems.length; i++) {
j('#' + valueItems[i]).attr('selected', 'selected');
j("#chkRoles ul li input[value=" + valueItems[i] + "]").parent().parent().parent().addClass("active");
var title = j("#chkRoles .btn-group").find("button").title;
j("#chkRoles .btn-group").find("button").removeAttr(title);
}
if (valueItems.length > 0) {
j("#chkRoles .btn-group").find("button").text(valueItems.length + ' selected');
}
else {
j("#chkRoles .btn-group").find("button").text('Select');
}
});
j(document.body).on('click', '#btnReset-Button', function () {
j("#divErrorMessage").hide();
j(this).parents('.PopupModalClass').find('input[type="text"],input[type="email"],select').each(function () {
if (this.defaultValue != '' || this.value != this.defaultValue) {
this.value = this.defaultValue;
setTimeout(function () {
j('.PopupModalClass #multiSelectDropdown').multiselect('refresh');
});
} else { this.value = ''; }
});
});
Kind of confused. I have a chunk of code for sorting nested li's that works. I copied the code into another page, and just changed a few class names to match the new pages elements. For the life of me, I cannot figure out why the same code is not working on the new page. Here is the code:
var is_sortable = true;
$(function () {
$('.packaging_move').bind("mousedown", packaging_add_sort);
function packaging_add_sort() {
//CHECK TO SEE IF THERE IS AN ACTIVE SORTABLE
if (is_sortable) {
//GET THE PARENT AND CURRENT ELEMENTS TO THE CLICKED ITEM
var parent = $(this).parent('div').parent('div').parent('li').parent('ul');
var current = $(this).parent('div').parent('div').parent('li');
//MAKE TRANSPARENT
current.animate({
opacity: 0.60
}, 100);
//PREVENT ANOTHER SORTABLE
is_sortable = false;
//CREATE SORTABLE
parent.sortable({
axis: 'y',
update: function () {
var parent_id = parent.attr("id");
var list = parent.sortable('serialize');
$.post("index.php?plugin=packaging&page=index", {
action: "packaging_rank",
parent: parent_id,
items: list
});
parent.sortable('destroy');
is_sortable = true;
},
stop: function () {
current.animate({
opacity: 1.0
}, 100);
parent.sortable('destroy');
is_sortable = true;
},
}).disableSelection();
//IF THERE IS AN EXISTING SORTABLE SHOW ERROR
} else {
zlcms_alert("Sorting Error", "You currently have an instance of sorting initiated. You may only sort one item at a time. Please complete the previous sort and try again.")
}
}
}
This is my first time really delving into jQuery with my ASP MVC3 intranet app. I need the autocomplete to be able to reference a list of items from a database. I followed the tutorial found here and thought "ok, that looks easy"... and now after implementing the code and researching other methods and bashing my head against the keyboard for at least four hours I'm not anywhere closer to making this work that before I wrote the code.
Here is the code from the view, w/the library declarations as well. FYI - I am taking over this project, so all the other javascript/Ajax you see was written by someone else with more experience than me. I put all the code in this section just in case something else is getting in the way.
<link href="../../Content/jquery-ui-1.9.2.custom.css" rel="stylesheet">
<script src="http://code.jquery.com/jquery-1.8.3.js" type="text/javascript"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$("#BankName").autocomplete({
source: '#Url.Action("GetBanks", "AgentTransmission")',
minLength: 1
});
$(function () {
$("#drpProducerType").change(function () {
var value = $(this).val();
if (value == "SoleProprietor") {
$("#Role").val(value);
$('#DSSfields').removeClass('noSee');
$('#DSSfields').addClass('seeMe');
//alert("Role must be set to \"Sole Proprietor\" as well. Monet will do this for you!");
}
else {
//TO DO: add role stuff here as well
$('#DSSfields').removeClass('seeMe');
$('#DSSfields').addClass('noSee');
}
});
$("#Role").change(function () {
var value = $(this).val();
if (value == "SoleProprietor") {
$("#drpProducerType").val(value);
alert("Producer Type changed to \"Sole Proprietor\" as well");
}
});
});
function ChangeChannel() {
//this function called if Market Segment changes, to update the channel
var pendistcode = document.getElementById('Pendist');
if (pendistcode == null) alert('Error: Cannot find Market Segment control');
$.ajax({
type: 'POST',
url: '/AgentTransmission/GetChannel/',
data: { pendist: pendistcode.value },
success: function (data) {
// alert("success: " + data);
$('#channelName').html(data);
$('#Channel').val(data);
},
error: function (data) {
alert("failure to obtain Channel name");
}
});
CheckTerritory('channel');
} //end ChangeChannel
function CheckTerritory(category) {
//this function called when changes happen that could change the territory (inddist)
//if the channel changed, or the alignment indicator, update the Territory
if ((category == "channel") | (category == "align")) UpdateTerritory();
//only trigger if the state or zip changed on the aligned address
if ((category == "L") && ($('#AlignmentL').attr('checked'))) UpdateTerritory();
if ((category == "M") && ($('#AlignmentM').attr('checked'))) UpdateTerritory();
} //end CheckTerritory
function UpdateTerritory() {
var i = $('#INDDist').val();
var p = $('#Pendist').val();
// alert(":" + i + ":" + p + ":");
//if ((i == "") || (p == "")) return;
if (p == "") return;
if ($('#INDDist').val() == "864") {
$('#INDDist').val("701");
}
else {
if ($('#INDDist').val() == "") {
$('#INDDist').val("864");
}
}
} //end UpdateTerritory
function MoreCompanies(row) {
//if the user clicks on the plus sign, add more company rows
if (row == '3') {
$('#plus2').html(' ');
$('#row3').removeClass('noSee');
$('#row3').addClass('seeMe');
}
if (row == '4') {
$('#plus3').html(' ');
$('#row4').removeClass('noSee');
$('#row4').addClass('seeMe');
}
if (row == '5') {
$('#plus4').html(' ');
$('#row5').removeClass('noSee');
$('#row5').addClass('seeMe');
}
} //end MoreCompanies
function CompanyFields() {
} //end CompanyFields
function ShowHideTerritory() {
alert('sunshine');
} //end ShowHideTerritory
</script>
The text box the autocomplete is supposed to work on
<div class="M-editor-label">
Bank\Agency Name
</div>
<div class="M-editor-field">
#Html.TextBoxFor(model => model.BankName, new { id = "BankName" })
#Html.ValidationMessageFor(model => model.BankName)
</div>
and here is the GetBanks method from the controller. I've set a breakpoint at the first line of this method and I've never been able to get it to hit.
//GET
public JsonResult GetBanks(string search)
{
var banks = from c in db.BankListMaster.Where(n => n.BankName.Contains(search))
select c.BankName;
banks = banks.Distinct();
return Json(banks, JsonRequestBehavior.AllowGet);
}
EDIT
If I replace the current .autocomplete code with the code suggested by this method instead , I get the following error in Chrome's debugger:
Uncaught Error: cannot call methods on autocomplete prior to initialization; attempted to call method '/AgentTransmission/GetBanks'
Here's the new code, I put it in the exact same spot as what I was previously using:
$(document).ready( function() {
$('#BankName').autocomplete('#Url.Action("GetBanks", "AgentTransmission")', {
dataType: 'json',
parse: function(data) {
var rows = new Array();
for(var i=0; i<data.length; i++){
rows[i] = { data:data[i], value:data[i].BankName };
}
return rows;
},
formatItem: function(row, i, n) {
return row.BankName + ' - ' + row.Description;
},
width: 300,
mustMatch: true,
});
});
I added an extra set of closing brackets to the autocomplete which cleared this up. The widget functions properly now.
$(function () {
$("#BankNameAuto").autocomplete({
source: '#Url.Action("GetBanks", "AgentTransmission")',
minLength: 1
});
});
I am currently porting a large application over to a HTML5 based web app - I have started building the app in AngularJS and enjoying the power of the AngularJS framework - I have one issue standing in my way currently:
I have a directive that gives me a jQuery Datepicker however the binding to the model does not seem to be working.
http://jsfiddle.net/9BRNf/
I am probably misunderstanding the way directives work and would like to see if I can patch this part of my understanding of the framework. I have gone through loads of examples (including the angularui project on github but still not making sense of why the binding is not happening)
any assistance will be greatly appreciated.
For those Googling this issue (as I was), a simpler way of tying in the jQuery UI datepicker with Angular is to do this...
$.datepicker.setDefaults({
// When a date is selected from the picker
onSelect: function(newValue) {
if (window.angular && angular.element)
// Update the angular model
angular.element(this).controller("ngModel").$setViewValue(newValue);
}
});
Just place it prior to your .datepicker() initialisation code.
(Taken from another answer I posted here: https://stackoverflow.com/a/17206242/195835)
First off, it's great that you are using angularjs, its a sweet framework. An offshoot project was started awhile back to deal with things like wrapping jquery-ui and creating ui modules.
Below is link to Peter Bacon Darwin's implementation.
https://github.com/angular-ui/angular-ui/tree/master/modules/directives/date
--dan
The angular-ui datepicker wasn't working with Angular 1.0.0, so I rewrote it. My fork gives you the ability to set how the date is formatted inside the input and how it gets saved back to the model.
Code: https://gist.github.com/2967979
jsFiddle: http://jsfiddle.net/m8L8Y/8/ (It's missing jquery-ui styles but works just the same)
// Code inspired by angular-ui https://github.com/angular-ui/angular-ui/blob/master/modules/directives/date/src/date.js
/*
Features:
* via the ui-date attribute:
* Ability to say how model is parsed into a date object
* Ability to say how input's value is parsed into a date object
* Ability to say how a date object is saved to the model
* Ability to say how a date object is displayed in the input
* via the ui-date-picker attribute
* Ability to directly configure the jQuery-ui datepicker
*/
angular.module('ui.directives', [])
.directive('uiDate', function () {
return {
require: '?ngModel',
//scope: {},
link: function ($scope, element, attrs, ngModel) {
// Date Handling Functions
var dateHandler = $.extend({ model: {}, view: {} }, $scope.$eval(attrs.uiDate));
// This will attempt to use preferredParser to parse a date.
function defaultDateParse(date, preferredParser) {
if (!preferredParser)
return new Date(date);
return preferredParser(date);
}
// This will attempt to use preferredFormatter to format a date, otherwise use 'mm/dd/yy'.
function defaultDateFormatter(date, preferredFormatter) {
if (!preferredFormatter)
preferredFormatter = "mm/dd/yy";
if (typeof preferredFormatter == 'string')
return $.datepicker.formatDate(preferredFormatter, date);
else
return preferredFormatter(date);
}
// Functions for Parsing & Formatting on the Model & View
function parseDateFromModel(date) {
return defaultDateParse(date, dateHandler.model.parse)
}
function parseDateFromView(date) {
return defaultDateParse(date, dateHandler.view.parse)
}
function formatDateForModel(date) {
return defaultDateFormatter(date, dateHandler.model.format)
}
function formatDateForView(date) {
return defaultDateFormatter(date, dateHandler.view.format)
}
var defaultDateViewFormat = (
typeof dateHandler.view.format == 'string'
? dateHandler.view.format
: 'mm/dd/yy'
)
// Initialize the jQuery-ui datePicker
var datePickerSettings = $.extend({ dateFormat: defaultDateViewFormat }, $scope.$eval(attrs.uiDatePicker))
var oldOnSelect = datePickerSettings.onSelect;
datePickerSettings.onSelect = function (dateVal) {
$scope.$apply(function () {
element.focus().val(dateVal);
updateModel();
})
if (oldOnSelect)
oldOnSelect.apply(this, arguments)
}
element.datepicker(datePickerSettings);
if (ngModel) {
// Specify how UI should be updated
ngModel.$render = function () {
element.val(ngModel.$viewValue || '');
};
// Listen for change events to enable binding
element.bind('blur keyup change', function () {
$scope.$apply(updateModel);
});
// Write data to the model
function updateModel() {
ngModel.$setViewValue(element.val());
}
// Convert the model into a string value
ngModel.$formatters.push(function (v) {
if (v != "" && v != null)
return formatDateForView(parseDateFromModel(v));
return null;
});
// Convert the string value into the model
ngModel.$parsers.push(function (v) {
if (v != "" && v != null)
return formatDateForModel(parseDateFromView(v))
return null;
});
}
}
};
})
Similar to praveepd (using their's as a base), but this will include deep model selection.
http://jsfiddle.net/c8PMa/
var myApp = angular.module('myApp', ['myApp.directives']);
function MainCtrl($scope) {
$scope.deepValue = {
fromDate: null,
toDate: null
}
}
angular.module('myApp.directives', [])
.directive('myDatepicker', function() {
return function(scope, element, attrs) {
element.datepicker({
changeYear : true,
changeMonth : true,
appendText : '(yyyy-mm-dd)',
dateFormat : 'yy-mm-dd',
onSelect: function(dateText) {
var mdlAttr = $(this).attr('ng-model').split(".");
if (mdlAttr.length > 1) {
var objAttr = mdlAttr[mdlAttr.length-1];
var s = scope[mdlAttr[0]];
for (var i=0; i < mdlAttr.length-2; i++) {
s = s[mdlAttr[i]];
}
s[objAttr] = dateText;
} else {
scope[mdlAttr[0]] = dateText;
}
scope.$apply();
}
});
}
});
http://jsfiddle.net/9BRNf/74/ here is the solution :)
code:
var myApp = angular.module('myApp', ['myApp.directives']);
function MainCtrl() {
}
angular.module('myApp.directives', [])
.directive('myDatepicker', function() {
return {
require: '?ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
element.datepicker({
changeYear : true,
changeMonth : true,
appendText : '(yyyy-mm-dd)',
dateFormat : 'yy-mm-dd',
onSelect: function(date) {
ngModelCtrl.$setViewValue(date);
scope.$apply();
}
});
}
}
});
Old question, but this was the first hit for me in google search for this. Anyways, I used dual datepickers working together using jquery and angular directives, so I thought I'd share to help anyone else trying to do this.
Here's the plunker for it:
http://plnkr.co/edit/veEmtCM3ZnQAhGTn5EGy?p=preview
Basically it initializes the form using json. The datepickers have their own conditions like mindate's, etc. The first select box if true = disables sundays on the calendars, else enables them.
The viewmodel get's updates when 'done' is clicked. Here's a bit of the code for one of the datepickers:
Html:
<input id="StartDate" data-ng-model="viewModel.startdate" date-from />
Directive:
app.directive('dateFrom', function() {
return function (scope, element, attrs) {
var doDate = $('#EndDate');
element.datepicker({
dateFormat: 'dd-M-yy', showOtherMonths: true,
selectOtherMonths: true, minDate: '0',
beforeShowDay: function (date) {
var day = date.getDay();
console.log(scope.nosunday);
if (scope.nosunday === 'true') return [(day !== 0), '']; // disable sundays
else return [true, ''];
},
onSelect: function (selectedDate) {
var toDate = new Date(element.datepicker("getDate"));
toDate.setDate(toDate.getDate() + 1);
doDate.datepicker('option', 'minDate', toDate);
scope.viewModel.startdate = selectedDate;
scope.viewModel.enddate = doDate.val();
}
});
}
})
Feel free to optimize it further. Post a comment with a forked plunk if you do :)
I had just trimmed the code, have a look at this: http://jsfiddle.net/YU5mV/
HTML
<input id="date1" value="1/1/1980" ng-model="fromDate" my-datepicker />
<input id="date2" value="1/1/1980" ng-model="toDate" my-datepicker />
JavaScript
angular.module('myApp.directives', [])
.directive('myDatepicker', function() {
return function(scope, element, attrs) {
element.datepicker({
changeYear : true,
changeMonth : true,
appendText : '(yyyy-mm-dd)',
dateFormat : 'yy-mm-dd',
onSelect: function(dateText) {
var mdlAttr = $(this).attr('ng-model');
scope[mdlAttr] = dateText;
scope.$apply();
}
});
}
});
How do I set watermark for a texbox in MVC3 .Also if there are multiple textboxes in a web page, how do you write different watermark text for each textbox?
<%:Html.TextBoxFor(mdl => mdl.inputTextSearch, Model.inputTextSearch )%>
Appreciate your response
If I understand your question, you can just pass in:
new { placeholder = "my watermark" }
as the htmlAttributes parameter in Html.TextBoxFor.
Edit:
You can also add support for older browsers by using Javascript as outlined here:
http://www.standardista.com/html5-placeholder-attribute-script
I usually just use the following jquery,for MVC project on fields which need a watermark: (the code compatible with IE 6 - 9, Firefox 2 - 4, safari 4.
$('#UserSearch').Watermark("Search term", "#fff");
/// JQuery Plugin code.
(function($) {
var map=new Array();
$.Watermark = {
ShowAll:function(){
for (var i=0;i<map.length;i++){
if(map[i].obj.val()==""){
map[i].obj.val(map[i].text);
map[i].obj.css("color",map[i].WatermarkColor);
}else{
map[i].obj.css("color",map[i].DefaultColor);
}
}
},
HideAll:function(){
for (var i=0;i<map.length;i++){
if(map[i].obj.val()==map[i].text)
map[i].obj.val("");
}
}
}
$.fn.Watermark = function(text,color) {
if(!color)
color="#aaa";
return this.each(
function(){
var input=$(this);
var defaultColor=input.css("color");
map[map.length]={text:text,obj:input,DefaultColor:defaultColor,WatermarkColor:color};
function clearMessage(){
if(input.val()==text)
input.val("");
input.css("color",defaultColor);
}
function insertMessage(){
if(input.val().length==0 || input.val()==text){
input.val(text);
input.css("color",color);
}else
input.css("color",defaultColor);
}
input.focus(clearMessage);
input.blur(insertMessage);
input.change(insertMessage);
insertMessage();
}
);
};
})(jQuery);
Using the MVC 3 standard, and an HTML5 compliant browser you can do:
#Html.TextBoxFor(mdl => mdl.inputTextSearch, new { placeholder = "my watermark" })
Try this Jquery .You need to create an image with the watermark text.
$(document).ready(function () {
/*Watermark for date fields*/
if ($("#dob").val() == "") {
$("#dob").css("background", "#ebebeb url('/Content/images/DateWaterMark.png') no-repeat 1px 0px");
}
$("#dob").focus(function () {
if (watermark == 'MM/DD/YYYY') {
$("#dob").css("background-image", "none");
$("#dob").css("background-color", "#fff");
}
}).blur(function () {
if (this.value == "") {
$("#dob").css("background", "#ebebeb url('/Content/images/DateWaterMark.png') no-repeat 1px 0px");
}
});
$("#dob").change(function () {
if (this.value.length > 0) {
$("#dob").css("background", "#fff");
}
});
}