I have this kendo grid that I add columns dynamically to it in something like this:
obj = {
field: field,
title: title,
editor: transactionDocumentTextEditor,
format: format,
headerTemplate: headerTemplate,
width: 40,
template: " <div class='documentBtn'><img src='../Images/document-disabled-icon.svg' border='0'></div> "
};
then later after adding all the columns I add them to the kendogrid columns,
the I made in editor this specific column to be clickable as :
function transactionDocumentTextEditor(container, options) {
if (options != null) {
var model = options.model;
var ItemTypesItemTypeID = model.ItemTypesItemTypeID;
var disabled = "";
if ((ItemTypesItemTypeID == 1) || (ItemTypesItemTypeID == 4) || (ItemTypesItemTypeID == 2))
disabled = " disabled ";
if (ItemTypesItemTypeID != "" && (ItemTypesItemTypeID == 3)) {
OpenDocumentUpload("ReceiveDocumentUpload.aspx?TransType=Stock", container);
currentContainer = container;
currentOptions = options;
}
}
}
function OpenDocumentUpload(path) {
var windowObj = parent.radopen("" + localStorage.controlsPath.toString() + "/Common/" + path, 'UserListDialog100', '300px', '300px');
windowObj.add_beforeClose(OnClientClose_DocumentWindow);
return true;
}
function OnClientClose_DocumentWindow(sender, args) {
var documentId;
if (sender.documentId != null) {
documentId = sender.documentId;
transactionDocumentTextEditorImage(currentContainer, documentId);
}
}
function transactionDocumentTextEditorImage(container, documentId) {
$("<div class='documentBtnEnabled'><input id='doc_ " + documentId + "' data-bind='value: " + documentId + "></div>")
.replaceAll(container)
}
now after using this editor I can add document and after closing the page and back to the grid, I call transactionDocumentTextEditorImage() so I can change the color of the picture to another picture that I have called in CSS, and it changes successfully.
But the problem is when I add another column to the kendo-grid, the template of the specific row that I changed the picture goes back to the default template that was before editing it, I searched about that issue but haven't found anything that specific, but I guess it should be something as an if condition in template ?
Thanks in advance
I have done some workaround and now it works,
I changed in OnClientClose_DocumentWindow :
function OnClientClose_DocumentWindow(sender, args) {
var documentId;
if (sender.documentId != null) {
documentId = sender.documentId;
$("#grid").data("kendoGrid").dataSource.getByUid(currentOptions.model.uid).transactionDocument = documentId;
transactionDocumentTextEditorImage(currentContainer,documentId);
}
}
then I changed template to :
obj = {
field: field,
title: title,
editor: editor,
format: format,
headerTemplate: headerTemplate,
width: 40,
template: "#if( data.transactionDocument == null || data.transactionDocument == ''){# #= GetTemp() # #} else {#<div class='documentBtnEnabled'></div>#}#"
};
I will keep the question just in case someone needs it
Related
In my Angularjs App, I'm creating dynamic table that also have a checkbox column and header of that column is also a checkbox for selectAll purpose.
Here is code of table creation
var dt = this;
// register function to call from dynamic html
dt.selectAll_Clicked = selectAll_Clicked;
var titleHtml = '';
titleHtml = '<input id="chkboxSelectAll" onClick="selectAll_Clicked()" type="checkbox">';
$('#dtData').DataTable().clear().destroy();
$("#invDiv").empty();
$("#invDiv").html("<table id='dtData' name='dtData' dt-options='dtOptions' dt-columns='dtColumns' class='table table-striped table-bordered'></table>");
var header = data[0],
dtColumns = [];
//create columns based on first row in dataset
for (var key in header) {
dtColumns.push(DTColumnBuilder.newColumn(key).withTitle(key));
}
dtColumns.push(DTColumnBuilder.newColumn(null).withTitle(titleHtml)
.renderWith(function(data, type, full, meta) {
return '<input type="checkbox" id="chkboxSelect' + data.Id + '" name="SelectClient" >';
}));
$scope.dtColumns = dtColumns;
//create options
$scope.dtOptions = DTOptionsBuilder.newOptions()
.withOption('data', data)
.withOption('dataSrc', '');
//initialize the dataTable
angular.element('#dtData').attr('datatable', '');
$compile(angular.element('#dtData'))($scope);
In selectAll_Clicked function, I'm getting Id(s) of all checkboxes and manually updating its checked property to true/false.
function selectAll_Clicked() {
if ($scope.lstSelectedData != null && $scope.lstSelectedData.length === $scope.lstData.length) {
$scope.lstSelectedData = [];
for (obj in $scope.lstData) {
document.getElementById("chkboxSelect" + $scope.lstData[obj].Id).checked = false;
}
} else {
$scope.lstSelectedData = [];
for (obj in $scope.lstData) {
console.log(document.getElementById("chkboxSelect" + $scope.lstData[obj].Id));
if (document.getElementById("chkboxSelect" + $scope.lstData[obj].Id).disabled == false) {
document.getElementById("chkboxSelect" + $scope.lstData[obj].Id).checked = true;
$scope.lstSelectedData.push($scope.lstData[obj].Id);
}
}
}
}
Its working fine with visible rows, but for invisible rows I'm facing issue
Uncaught TypeError: Cannot read property 'disabled' of null
document.getElementById returns null for invisible rows.
I tried this alternative solution. It returns definition of cell but it does not allow to update properties of that cell.
Is there any other way to do this?? Any kind of help will be appreciated.
i want to build mini webchat - When view site i set show 5 messages and if view more, you can click button. All things are fine but when i remove 1 node, firebase auto add last node into, how can i prevent it?
Ex: I have node A,B,C,D,E,F,G. I had loaded list C,D,E,F,G but when i delete 1 in all, it auto add B into list.
<div id="messgesDiv">
<center><h3>Message</h3></center>
</div>
<div style="margin-top: 20px;">
<input type="text" id="nameInput" placeholder="Name">
<input type="text" id="messageInput" placeholder="Message" data-id="">
<input type="text" id="idproject" placeholder="ID Project">
</div>
<button id="delete">Delete Test</button>
<button id="edit">Edit</button>
<button id="loadmore">Load more</button>
<button id="showlastkey">Show last key</button>
My javascript
$('#loadmore').click(function() {
i = 0; old = first;
myDataRef.orderByKey().endAt(first).limitToLast(6).on('child_added', function (snapshot){
if( i == 0)
first = snapshot.key();
var message = snapshot.val();
if(snapshot.key() != old)
displayChatMessage(message.name, message.text, message.idproject, 'old');
i++;
console.log('myDataRef.orderByKey().endAt(first).limitToLast(6)');
});
});
$("#messageInput").keypress(function (e){
if(e.keyCode == 13){ //Enter
var name = $("#nameInput").val();
var text = $("#messageInput").val();
var idproject = $("#idproject").val();
if($("#messageInput").data("id")=='')
{
myDataRef.push({name: name, text: text, idproject: idproject});
}
else
{
myDataRef.child(key).update({name: name, text: text, idproject: idproject});
$('#messageInput').attr('data-id', '');
}
$("#messageInput").val("");
}
});
myDataRef.limitToLast(5).on('child_added', function (snapshot){
if( i == 0)
first = snapshot.key();
var message = snapshot.val();
displayChatMessage(snapshot.key(), message.name, message.text, message.idproject, 'new');
i++;
console.log(snapshot.key());
console.log(' myDataRef.limitToLast(5)');
});
function displayChatMessage(key, name, text, idproject, status){
//console.log(name + " -- " + text + " -- " +idproject);
if( status == 'new')
{
$('<div/>', { 'data-id': key , 'class' : 'test'}).text(text + " - ").prepend($('<em/>').text(name+": " )).append("IdProject: "+idproject).appendTo($("#messgesDiv"));
$("#messgesDiv")[0].scrollTop = $("#messgesDiv")[0].scrollHeight;
}
else
{
$('<div/>', { 'data-id': key , 'class' : 'test'}).text(text + " - ").prepend($('<em/>').text(name+": " )).append("IdProject: "+idproject).insertAfter($("center"));
$("#messgesDiv")[0].scrollTop = $("#messgesDiv")[0].scrollHeight;
}
}
$('#delete').click(function() {
myDataRef.child(key).remove();
$('#messgesDiv').filter('[data-id="'+key+'"]').remove();
});
Firebase limit queries act like a view on top of the data. So if you create a query for the 5 most recent messages, the Firebase client will ensure that you always have the 5 most recent messages.
Say you start with these messages:
message1
message2
message3
message4
message5
Now if you add a message6, you will get:
child_removed message1
child_added message6
So that your total local view becomes:
message2
message3
message4
message5
message6
Conversely when you remove message 6 again, you get these events:
child_removed message6
child_added message1 (before message2)
So that you can update the UI and end up with the correct list again.
There is no way to change this behavior of the API. So if you want to handle the situation differently, you will have to do this in your client-side code.
Your code currently only handles child_added. If you have add a handler for child_removed you'll see that you can easily keep the user interface in sync with the data.
Alternatively you can detect that the message is already in your UI by comparing the key of the message you're adding to the ones already present in the DOM:
function displayChatMessage(key, name, text, idproject, status){
var exists = $("div[data-id='" + key + "']").length;
if (status == 'new' && !exists) {
$('<div/>', { 'data-id': key , 'class' : 'test'}).text(text + " - ").prepend($('<em/>').text(name+": " )).append("IdProject: "+idproject).appendTo($("#messgesDiv"));
$("#messgesDiv")[0].scrollTop = $("#messgesDiv")[0].scrollHeight;
}
else {
$('<div/>', { 'data-id': key , 'class' : 'test'}).text(text + " - ").prepend($('<em/>').text(name+": " )).append("IdProject: "+idproject).insertAfter($("center"));
$("#messgesDiv")[0].scrollTop = $("#messgesDiv")[0].scrollHeight;
}
}
Is it possible to pass a function to the tooltip key in the Zingchart Json?
I tried the following so far:
$scope.applyTooltip = function (timestamp) {
console.log(timestamp);
var tooltip = "<div>";
var data = {
timestamp1: {
param1: "bla",
param2: "foo,
},
...
}
for(var param in data){
console.log(param);
tooltip += param+": "+data[param]+"<br>";
}
tooltop += "</div>;
return tooltip;
}
$scope.graphoptions = {
//...
//just displaying the relevant options
plot: {
"html-mode": true,
tooltip: $scope.applyTooltip("%kt"),
}
}
}
But the function gets the string "%kt" as it is and not the wanted X-Value of the hovered Plot. So how is it possible to pass the X-Value in the Function?
ZingChart does not allow passing in functions through the configuration object.
Instead, there is a property called "jsRule" which allows you to pass the name a function to be evaluated during each tooltip event.
tooltip : {
jsRule : "CustomFn.formatTooltip()"
}
Inside that function, a parameter will be available that will contain information about the node you moused over such as value, scaletext, plotindex, nodeindex, graphid, and more. Simply return an object for the tooltip (including the formatted text) and ZingChart will take care of the rest. Example provided down below.
The one caveat to jsRule is that the function name has to be accessible globally since ZingChart does not accept inline functions. We are aware of this issue and are planning for this to be an option in future versions.
CustomFn = {};
var myConfig = {
type: "line",
tooltip : {
jsRule : "CustomFn.formatTooltip()"
},
series : [
{
values : [1,3,2,3,4,5,4,3,2,1,2,3,4,5,4]
},
{
values : [6,7,8,7,6,7,8,9,8,7,8,7,8,9,8]
}
]
};
CustomFn.formatTooltip = function(p){
var dataset = zingchart.exec('myChart', 'getdata');
var series = dataset.graphset[p.graphindex].series;
var tooltipText = "";
for (var i=0; i < series.length; i++) {
tooltipText += "Series " + i + " : " + series[i].values[p.nodeindex] + "";
if (i !== series.length-1) {
tooltipText += "\n";
}
}
return {
text : tooltipText,
backgroundColor : "#222"
}
}
zingchart.render({
id : 'myChart',
data : myConfig,
height: 400,
width: 600
});
<!DOCTYPE html>
<html>
<head>
<script src= 'https://cdn.zingchart.com/2.3.1/zingchart.min.js'></script>
</head>
<body>
<div id='myChart'></div>
</body>
</html>
In my entity (A) has 50 option set. If the user select 10 optionsset value and not selected remaining one, and he/she click save button. In that situation i need to alert user "To fill all the option set". I don't want to get the Schema name for the optionset individually, i need to get all the option set schema name dynamically.
Is it possible? Help me.
I have not tested this function, but you can try this and make changes if needed.
function IsFormValidForSaving(){
var valid = true;
var message = "Following fields are required fields: \n";
Xrm.Page.data.entity.attributes.forEach(function (attribute, index) {
if (attribute.getRequiredLevel() == "required") {
if(attribute.getValue() == null){
var control = attribute.controls.get(0);
// Cheking if Control is an optionset and it is not hidden
if(control.getControlType() == "optionset" && control.getVisible() == true) {
message += control.getLabel() + "\n";
}
valid = false;
}
}
});
if(valid == false)
{
alert(message);
}
}
Ref: Microsoft Dynamics CRM 2011 Validate required form javascript
Required fields individual alert fire before the on save event. If you wish to prevent the single alert routine for all unfilled option sets you need to remove the requirement constraint and manage the constraint yourself, probably in your on save handler. I’m just writing the idea here (not tested).
// enter all optionsets ids
var OptionSets50 = ["new_optionset1","new_optionset2","new_optionset50"];
var dirtyOptions = [];
function MyOptionSet(id) {
var mos = this;
var Obj = Xrm.Page.getAttribute(id);
var Ctl = Xrm.Page.getControl(id);
Obj.addOnChange(
function () {
if (Obj.getValue() != null)
delete dirtyOptions[id];
else
dirtyOptions[id] = mos;
});
this.GetLabel = function() {
return Ctl.getLabel();
}
if (Obj.getValue() == null)
dirtyOptions[id] = mos;
}
function OnCrmPageLoad() {
for(var x in OptionSets50) {
OptionSets50 [x] = new MyOptionSet(OptionSets50 [x]);
}
Xrm.Page.data.entity.addOnSave(OnCrmPageSave);
}
//check for dirty options and alert
function OnCrmPageSave(execContext) {
var sMsg = "The following Optinsets Are Required: ";
var sLen = sMsg.length;
for(var os in dirtyOptions) {
sMsg += dirtyOptions[os].GetLabel() + "\n";
}
if (sMsg.length > sLen) {
execContext.getEventArgs().preventDefault();
alert(sMsg);
}
}
I am trying to use the "onreset" option but I am having issues. I have a field that is meant for users to enter 10 numbers only. I want to make the 10 numbers display in a phone format ie. (310) 490-1235. So far I can do this, and the HTML of the field gets set to 3104901235 while the text is (310) 490-1235, but when a user cancels or goes to another field, the current field closes, and displays the HTML (3104901235) instead of the text (310) 490-1235.
I have a function set in the "onreset" option for it to set the text but it doesnt apply.
//Phone field
// Set the fields 10 digits to phone format
set_phone();
function isNumeric(value) {
if (value == null || !value.toString().match(/^[-]?\d*\.?\d*$/)) return false;
return true;
}
$('.edit-phone').editable('<?php echo base_url(); ?>home_resume/builder/ajax_save_field', {
onsubmit: function(settings, td) {
rm_class();
var input = $(td).find('input');
var original = input.val().trim();
if (isNumeric(original) && original.length == 10) {
$('#notification-saved').miniNotification({opacity: 1.0});
return true;
} else {
$('#notification-phone').miniNotification({opacity: 1.0});
input.css('background-color','#c00').css('color','#fff');
return false;
}
},
type : 'text',
cancel : 'Cancel',
onreset : function(value, settings){
$(this).closest("li").removeClass("active");
// Since the HTML is now just 10 digits, set it back to phone format with
set_phone();
},
style : 'display: inline',
select : 'true',
submit : 'OK',
event : "edit-phone",
indicator : '<img src="<?php echo base_url(); ?>themes/resume-builder/images/fb-indicator.gif">'
});
$(".edit-phone-trigger").on("click", function() {
strip_phone();
$(this).closest("li").addClass('active');
var edit_id = $(this).attr("id").split("-");
$('#' + edit_id[1]).trigger("edit-phone");
return false;
});
// Format the 10 digit phone number
function set_phone() {
var num = $("#7").text();
var num_1 = num.slice(0,3);
var num_2 = num.slice(3,6);
var num_3 = num.slice(6,11);
var new_num = "("+num_1+") "+num_2+"-"+num_3;
$("#7").text(new_num);
}
// Remove characters from phone number input
function strip_phone() {
var pnum = $("#7").text();
pnum = pnum.replace(/\(/g, "");
pnum = pnum.replace(/\)/g, "");
pnum = pnum.replace(/-/g, "");
pnum = pnum.replace(/\s/g, "");
$("#7").html(pnum);
}
You can try using the data and callback options for changing the way the text is displayed inside the input, this way you also avoid the need to use your custom event.
data will be called when the element is first clicked and can be used to alter the text before editing. Here you strip the phone to just numbers to be displayed on the input.
callback will run after after the form has been submitted. Here you format the submitted content to a phone number and change the text of the original element. (Inside function this refers to the original element)
$('.edit-phone').editable('<?php echo base_url();?>home_resume/builder/ajax_save_field', {
type : 'text',
cancel : 'Cancel',
style : 'display: inline',
select : 'true',
submit : 'OK',
event : 'click',
indicator : '<img src="<?php echo base_url(); ?>themes/resume-builder/images/fb-indicator.gif">',
data : function(value, settings) {
return strip_phone(value);
},
callback : function(value, settings){
$(this).text(set_phone(value));
}
onsubmit : function(settings, td) {
rm_class();
var input = $(td).find('input');
var original = input.val().trim();
if (isNumeric(original) && original.length == 10) {
$('#notification-saved').miniNotification({opacity: 1.0});
return true;
} else {
$('#notification-phone').miniNotification({opacity: 1.0});
input.css('background-color','#c00').css('color','#fff');
return false;
}
},
});
// Format the 10 digit phone number
function set_phone(text) {
var num = text;
var num_1 = num.slice(0,3);
var num_2 = num.slice(3,6);
var num_3 = num.slice(6,11);
var new_num = "("+num_1+") "+num_2+"-"+num_3;
return new_num;
}
// Remove characters from phone number input
function strip_phone(text) {
var pnum = text;
pnum = pnum.replace(/\(/g, "");
pnum = pnum.replace(/\)/g, "");
pnum = pnum.replace(/-/g, "");
pnum = pnum.replace(/\s/g, "");
return pnum;
}
Note that I updated your set_phone() and strip_phone() functions to return the value instead of setting it directly to the element so they can be called dynamically