I am trying to add an option to a select element. The value is being given by a user form in a jquery ui modal.
When I use Chrome Developer tools, I can see that the bound object array is indeed getting the new object, but it's not showing up in the select element.
I used $('#company').scope().vendors in the console to bring up the array. It shows items being added to the array, but they aren't showing in the select box.
Here is what I have:
app.js
app.factory('Vendors', function(){
var Vendors = {};
Vendors.list = [
{
id: 1,
name: 'Company 1'
},
{
id: 2,
name: 'Company 2'
},
{
id: 3,
name: 'Company 3'
}
]
return Vendors;
})
app.controller('companyCtrl', function($scope, Vendors){
$scope.vendors = Vendors;
$scope.selectedVendor = 0;
$scope.companySelect = function(){
alert("You chose " + $scope.selectedVendor.name)
}
$scope.addCompany = function(name){
var maxId = 0;
for(var i=0; i<$scope.vendors.list.length; i++){
maxId = $scope.vendors.list[i].id;
}
newVendor = {id:++maxId, name:name};
$scope.vendors.list.push(newVendor)
$scope.selectedVendor = newVendor;
}
})
HTML
<div class="row">
<div class="grid_12" ng-controller="companyCtrl" id="company">
<span>Company</span>
<select ng-model="selectedVendor" ng-change="companySelect()" ng-options="v.name for v in vendors.list">
<option value="">-- Choose Company --</option>
</select>
<small><button onclick="openModal('addCompany');">Add</button></small>
</div>
</div>
Inline JS
$( "#addCompany" ).dialog({
autoOpen: false,
width: 350,
modal: true,
buttons: {
"Create new company": function() {
var name = $('#name').val();
if(name != ''){
$('#company').scope().addCompany(name);
}
$( this ).dialog( "close" );
},
Cancel: function() {
$( this ).dialog( "close" );
}
},
close: function() {
$('#name').val( "" );
}
});
function openModal(id){
$('#'+id).dialog('open');
}
I tried creating a jsFiddle, but I guess I'm not too sure how to get everything on there to work yet. But here is my try anyway: http://jsfiddle.net/aPXxe/
Try this:
$scope.$apply(function(){
$scope.vendors.list.push(newVendor);
$scope.selectedVendor = newVendor;
});
Related
I am working on creating a new context menu that provides more accessibility. The old menu was using the context menu ID's to check conditions with tal in Index.html. My issue now is that I am no longer using action and not using the ID's. The new context menu is creating each menu with a different ID. I tried declaring "var emp_menu_items = [];" in a script tag inside the condition and removing it from the Employee class but I'm still getting error that it is undefined.
I also tried building the new context menu in Index.html but it needs parameters that are inside of Employee.js. So is there a solution to use the tal:conditions in a JS file?
Index.html
<a metal:fill-slot="context_menus" tal:omit-tag="">
<ul id="employee_context_menu" class="hidden" tal:define="sec_posted python:container.util.checkSecurity(mn_name='Posted')">
<li tal:condition="python:layout == 'np'">Assign Patients</li>
<li tal:condition="python:container.util.checkSecurity(mn_name='File')">HR File</li>
<li tal:condition="python:sec_posted">Pay Period Schedule</li>
<li>Close Menu</li>
</ul>
This is the old menu in Employee.js class
$name.contextMenu({
menu: "employee_context_menu",
leftClick: true
}, function(action, elem, position) {
if(action == 'Close') {
jQuery(".contextMenu").hide();
return true;
} else if(action === 'hr_file') {
$iframe.attr('src', 'Personnel/cgi_utran/cgi_utran?args=-i'+$div.data('obj').id).load(function() {resizeIframe(this)});
} else if(action === 'assign_pat') {
$j.PatientAssignment.assign_check = emp.id;
$name.addClass('highlight');
var title_str ='Assign Patients to ' + employee_name;
$j.PatientAssignment.sub_title = ''
var mheight = $j(window).height()*0.7;
$j('#beds').dialog('close');
$j('#beds').css('max-height',mheight).dialog({
modal: false,
title: title_str,
height:'auto',
width: 'auto',
close: function() { $name.removeClass('highlight'); }
});
syncPatientAssignments();
syncBedAssignments();
return true;
} else if(action === 'schedule') {
$iframe.attr('src', 'ScheduleStaff/cgi_daystaff?szDate='+emp.shiftdate+'&szID='+emp.id+'&args=-t').load(function() {resizeIframe(this)});
} else if(action === 'assign_work') {
$iframe.attr('src', 'ScheduleStaff/cgi_daystaff?args=-t OneEmployee -I'+emp.id+' -B'+emp.shiftdate).load(function() {resizeIframe(this)});
} else { }
$name.addClass('highlight');
$j("#modal_window").dialog({
modal: true,
width: 'auto',
show: 'scale',
hide: 'scale',
height: 'auto',
close: function() {window.location.reload(); $name.removeClass('highlight'); }
});
});
My changes to the context menu in Employee.js
employeeContextMenu($div, emp, employee_name, count) {
var emp_menu_items = [];
var emp_menu = {};
emp_menu_items.push({
name: 'Assign Patients', title: 'Assign Patients',
fn: function(el) {
$j.PatientAssignment.assign_check = emp.id;
var title_str ='Assign Patients to ' + employee_name;
$j.PatientAssignment.sub_title = ''
var mheight = $j(window).height()*0.7;
if ($j('#beds').hasClass("ui-dialog-content") && $j( "#beds" ).dialog( "isOpen" )){
$j('#beds').dialog('close');
}
$j('#beds').css('max-height',mheight).dialog({
modal: false,
title: title_str,
height:'auto',
width: 'auto',
position: [670, 115],
focus: function(event,ui) {
$j(".ui-icon-closethick").focus();
},
buttons: {
OK: function(){
$j(this).dialog("close");
}
}
});
syncPatientAssignments();
syncBedAssignments();
}
});
emp_menu_items.push({
name: 'HR File', title: 'HR File',
fn: function(el){return pop_over_window('Personnel/cgi_utran/cgi_utran?args=-i'+$div.data('obj').id);}});
emp_menu_items.push({
name: 'Pay Period Schedule', title: 'Pay Period Schedule',
fn: function(el){return pop_over_window('ScheduleStaff/cgi_daystaff?szDate='+emp.shiftdate+'&szID='+emp.id+'&args=-t');}});
emp_menu_items.push({
name: 'Close Menu', title: '',
fn: function(el){return false}, });
emp_menu = new ContextMenu('employee_context_menu_'+count, 'Employee Context Menu Options', '.name', emp_menu_items, {container:$div[0]});
}
I guess what you are looking for is to use server-side code inside a javascript "file" (I presume from the tagging of your question that you are working in Zope, so the javascript would be contained in an object in the ZODB).
Create your Employee.js as a DTML Method or DTML Document or Script (Python) to this end.
In the DTML objects, instead of tal-conditions, you can use <dtml-if>my js code<dtml-else>more js code</dtml-if> and any other DTML construct.
Of course you could also write a Python Script that returns the javascript code.
I found this example which highlights a row after it has been selected but the problem with it is that it keeps the previous row(s) highlighted after another one has been selected.
Here's part of the code
//js
rowClick: function(args) {
var $row = this.rowByItem(args.item);
$row.toggleClass("highlight");
},
//css
tr.highlight td.jsgrid-cell {
background-color: green;
}
I can't find a solution to unhighlight the previously selected row
A little late to the party on this one, however the accepted answer by #Narenda didn't completely solve my problem. This may help someone else that stumbles across this later.
If you need a single select only, here's a way of doing it:
Extend the jsGrid plugin with a method to find a row by index:
jsGrid.Grid.prototype.rowByIndex = function(arg){
//this._content.find("tr")[arg] returns a DOM element instead of a jQuery object
//Pass the DOM element to the find method to get a jQuery object representing it
return this._content.find(this._content.find("tr")[arg]);
};
Modify the rowClick function in #Narenda's answer:
rowClick: function ( args ) {
//Deselect all rows
for(var i = 0; i<this.data.length; i++){
this.rowByIndex(i).removeClass("jsgrid-highlight-row");
}
//Everything else as per the previous answer
var $row = this.rowByItem(args.item),
selectedRow = $("#jsGrid").find('table tr.jsgrid-highlight-row');
if (selectedRow.length) {
selectedRow.toggleClass('jsgrid-highlight-row');
};
$row.toggleClass("jsgrid-highlight-row");
//Any other code to run on item click
}
And add some CSS. This mimics the row hover in the default theme:
tr.jsgrid-highlight-row td.jsgrid-cell {
background:#c4e2ff;
border-color:#c4e2ff;
}
You can achieve by this following steps
First on row click you need to get selected row like this
var selectedRow = $("#jsGrid").find('table tr.highlight').
Then you can use
selectedRow.toggleClass('highlight') or selectedRow.removeClass('highlight')
DEMO
$("#jsGrid").jsGrid({
width: "100%",
height: "auto",
paging: false,
//for loadData method Need to set auto load true
autoload: true,
noDataContent: "Directory is empty",
controller: {
loadData: function(filter) {
var data = [{
nickname: "Test",
email: "t#gmail.com"
}, {
nickname: "Test 1",
email: "t1#gmail.com"
}, {
nickname: "Test 2",
email: "t2#gmail.com"
}, {
nickname: "Test 3",
email: "t3#gmail.com"
}];
return data;
}
},
rowClick: function(args) {
var $row = this.rowByItem(args.item),
selectedRow = $("#jsGrid").find('table tr.highlight');
if (selectedRow.length) {
selectedRow.toggleClass('highlight');
};
$row.toggleClass("highlight");
},
fields: [{
name: "nickname",
type: "text",
width: 80,
title: "Name"
}, {
name: "email",
type: "text",
width: 100,
title: "Email Address",
readOnly: false
}]
});
tr.highlight td.jsgrid-cell {
background-color: green;
}
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid-theme.min.css" />
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid.min.js"></script>
<div id="jsGrid"></div>
If you came looking for a solution in which only 1 line is selected and which also deselects the same line, here is the solution:
selectedVal = null;
$(document).ready(function(){
jsGrid.Grid.prototype.rowByIndex = function(arg) {
//this._content.find("tr")[arg] returns a DOM element instead of a jQuery object
//Pass the DOM element to the find method to get a jQuery object representing it
return this._content.find(this._content.find("tr")[arg]);
};
});
rowClick: function (args) {
selectedVal = args.item;
let $row = this.rowByItem(args.item);
if ($row.hasClass("highlight") === false) {
//Deseleciona todas as linhas
for (let i = 0; i < this.data.length; i++) {
this.rowByIndex(i).removeClass("highlight");
}
$row.toggleClass("highlight");
} else {
selectedVal = null;
$row.toggleClass("highlight");
}
console.log(selectedVal);
}
I have a dojo dialog function and want to be able to add a table with 5 rows to it. How can I do this? Below is the code I have.
dojo.require("dijit.Dialog");
dojo.require("dijit.form.TextBox");
dojo.require("dojox.grid.EnhancedGrid");
dojo.addOnLoad(function() {
popup = new dijit.Dialog({
title: "Non-Spatial Permanent Feature Deductions...",
style: "width: 750px; height: 400px",
content: "<input dojoType='dijit.form.Button' type='button' name='name' id='name' label='OK'>"
});
popup.show()
});
If your table row is fixed i.e 5 than you may be do one simply thing that create a html file have table of 5 rows and call that file inside dialog.
popup = new dijit.Dialog({
title: "Non-Spatial Permanent Feature Deductions...",
style: "width: 750px; height: 400px",
href:"table.html"
});
When I need a dialog that has a bunch of dijits or custom functionality I end up making a custom dialog dijit. Here's one of my from a current project.
define([
"dojo/_base/declare",
"dijit/_Widget",
"dijit/_TemplatedMixin",
"dijit/_WidgetsInTemplateMixin",
"dojo/i18n!magic/nls/common",
"dojo/text!./templates/emrSelection.html",
"dojo/dom-construct",
"dojo/on",
"dojo/Evented",
"dojo/_base/connect",
"dojo/query",
"dojo/_base/lang",
"dijit/Dialog",
"dijit/form/CheckBox"
],
function (declare, _Widget, _TemplatedMixin, _WidgetsInTemplateMixin, i18n, template, domConstruct, on, Evented, connect, query, lang, Dialog, CheckBox) {
return declare("project.customDialog", [Dialog], {
title: i18n.customDialog.title,
emrIds: [],
constructor: function(/*Object*/ kwArgs) {
lang.mixin(this, kwArgs);
var contentWidget = new (declare([_Widget, _TemplatedMixin, _WidgetsInTemplateMixin], {
closeLabel: i18n.close,
templateString: template,
baseClass: "customDialog"
}));
contentWidget.startup();
this.content = contentWidget;
},
postCreate: function() {
this.inherited(arguments);
},
startup: function() {
this.inherited(arguments);
this._createTable();
},
_createTable : function() {
var that = this;
var i = 0;
var tr = null;
this.store.query().forEach(lang.hitch(this, function(emr){
var state = that.emrIds.indexOf(emr.id) != -1;
if(i++%3 == 0) {
tr = domConstruct.create("tr");
domConstruct.place(tr, that.content.tableBody);
}
var td1c = domConstruct.create("td", {'class':"checkBox"}, tr);
var td1l = domConstruct.create("td", {'class':"label"}, tr);
var box = that._createCheckBox(emr.name, state, emr.id);
domConstruct.place(box.domNode, td1c);
domConstruct.place("<label for='checkbox'>"+emr.name+"</label>", td1l);
}));
},
_createCheckBox : function(name, checked, id) {
var box = CheckBox({
name: name,
value: name,
checked: checked,
emr_id: id,
onChange: lang.hitch(this, function(state){
var id = box.get('emr_id');
var name = box.get('name');
this.emit("tick", {emrId:id, name:name, state:state});
})
}, domConstruct.create("div"));
box.startup();
return box;
}
});
the template
<div class="${baseClass}" data-dojo-attach-point="container" >
<table>
<tbody data-dojo-attach-point="tableBody"></tbody>
</table>
<div class="buttonContainer">
<button class="button" data-dojo-type="dijit.form.Button" data-dojo-attach-point="saveButton">${closeLabel}</button>
</div>
</div>
and then i call it with and use on() to get events from it.
this.dialog = new emrSelection({store: this.emrStore, emrIds: this.emrIds});
this.dialog.startup();
this.dialog.show();
I am working a on slickgrid where one cell needs to show a dropdown (selectlist) with values coming from a restful service. These values are different for each row.
I should be able to select one value from this list (dropdown) and it should persist the value in the cell.
I would be glad if someone could help with this problem.
this.productColumns = [
{
id: 'statusid',
name: 'Status',
field: 'statusid',
width: 65,
sortable: true
},
{
id: 'grade',
name: 'Grade',
field: 'grade',
width: 80,
sortable: true
},
{
id: 'position',
name: 'Position',
field: 'originalPosition',
width: 80,
sortable: true
},
{
id: 'tyresize',
name: 'Tyre Size',
field: 'tyreSize',
editable: true,
width: 140,
sortable: true
},
{
id: 'tyredetail',
name: 'Tyre Detail',
field: 'tyredetail',
editable: true,
width: 125,
editor: this.selectRangeEditor
}
]
selectRangeEditor: function (args) {
var $select = $("");
var defaultValue = "";
var scope = this;
this.init = function () {
var tyreOptionsList = new TyreOptionsModel(args.item.id);
tyreOptionsList.deferred.done(function () {
var opt_values = tyreOptionsList.toJSON();
var count = 0;
for (var cnt in opt_values) {
if (opt_values.hasOwnProperty(cnt)) {
count++;
}
}
option_str = ""
var i ;
for (i = 0; i < count-1; i++) {
val = opt_values[i].tyreOptionId;
txt = opt_values[i].tyreDetail;
option_str += "<OPTION value='" + val + "'>" + txt + "</OPTION>";
}
$select = $("<SELECT tabIndex='0' class='editor-select'>" + option_str + "</SELECT>");
$select.appendTo(args.container);
$select.focus();
});
};
this.destroy = function () {
$(args.container).empty();
};
this.focus = function () {
$select.focus();
};
this.serializeValue = function () {
return $select.val();
};
this.applyValue = function (item, state) {
item.attributes[args.column.field] = state;
};
this.loadValue = function (item) {
defaultValue = item.attributes[args.column.field];
$select.val(defaultValue);
};
this.isValueChanged = function () {
return ($select.val() != defaultValue);
};
this.validate = function () {
return {
valid: true,
msg: null
};
};
this.init();
return $select.val();
}
Did you see my answer to this question ?
If you are able to get the options from the rest service for each row while generating the page, you can just use my solution at the client side ...
As I understand from you comment, the problem is how to postback the changes made in the grid after the user changed some fields ...
I solved this by adding the following piece of code, notice the JS code for the form submit, handle this incoming data at the server side, to save it using the RESTfull service.
<div id="myGrid" style="width:90%;height:250px;"></div>
<form action="" method="POST">
<input id="save_grid_changes" disabled="disabled" type="submit" value="Save changes to {{obj_type}}(s)">
<input type="hidden" name="obj_type" value="{{obj_type}}">
<input type="hidden" name="data" value="">
</form>
<script>
$(document).ready(function() {
grid = new Slick.Grid($("#myGrid"), griddata, columns, options);
$("form").submit(
function() {
// commit the last edit ...
grid.getEditController().commitCurrentEdit();
grid.resetCurrentCell();
$("input[name='data']").val( $.toJSON(griddata) );
// ("input[name='data']").val($.param(data));
});
});
</script>
I'm getting a firebug error:
missing : after property id
error source line:
if(jQuery.inArray(mmDialogButton.CANCEL, buttons)){
This is the surrunding code:
Edited post with update as I was unclear.
I am trying to create a framework for creating dialogues for a project.
In the dialogs there can be four predefined buttons.
The mmDialogButton is my attempt to an ENUM class.
The if statement is there to enable the buttons the user wanted to use in the dialog.
Here is some more code to illustrate.
mmDialog.js
...
function mmDialog(title, spawnerId, widget, buttons){
...
$dialog.html(widget.getInitialHTML())
.dialog({
autoOpen: false,
title: title + ' <img id="myJquerySpinner" />',
buttons: {
if(jQuery.inArray(mmDialogButton.CANCEL, buttons)){
Cancel: function() {
$( this ).dialog( "close" );
},
}
if(jQuery.inArray(mmDialogButton.NEXT, buttons)){
"Next": function() {
widget.doNext();
},
}
if(jQuery.inArray(mmDialogButton.PREVIOUS, buttons)){
"Previous": function() {
widget.doPrevious();
},
}
if(jQuery.inArray(mmDialogButton.OK, buttons)){
"Ok": function() {
widget.doOk();
}
}
}...
mmDialogButton.js
function mmDialogButton(){ // Constructor
}
mmDialogButton.CANCEL = function() { return "mmDBCancel"; };
mmDialogButton.OK = function() { return "mmDBOk"; };
mmDialogButton.NEXT = function() { return "mmDBNext"; };
mmDialogButton.PREVIOUS = function() { return "mmDBPrevious"; };
jsp/html page
var title = "Test Dialog";
var spawnerId = "myJqueryStarter";
var mmDialogButtons = new Array();
mmDialogButtons[0] = mmDialogButton.CANCEL;
mmDialogButtons[1] = mmDialogButton.OK;
mmDialogButtons[2] = mmDialogButton.NEXT;
mmDialogButtons[3] = mmDialogButton.PREVIOUS;
myPublishWidget = new mmPublishWidget();
myDialogPublishWidget = new mmDialogWidget(myPublishWidget);
myDialog = new mmDialog(title, spawnerId, myDialogPublishWidget , mmDialogButtons);
This:
buttons: {
if(jQuery.inArray(mmDialogButton.CANCEL, buttons)){
Cancel: function() {
$( this ).dialog( "close" );
},
should probably be:
buttons: (function() {
if(jQuery.inArray(mmDialogButton.CANCEL, buttons))
return {
Cancel: function() {
$( this ).dialog( "close" );
}
};
return null;
})()
though it's hard to tell. What it looks like you're trying to do is conditionally set that "buttons" property to some object with a labeled handler (that little "close" function). However, the code you posted is syntactically nonsensical. The change I made wraps the "inArray" test in an anonymous function that returns the button object only when that test is true.
Again, I'm just guessing that that's what you were trying to do.
I think you mean to execute the "close" only if CANCEL is in buttons, if it's the case you can write:
buttons: {
Cancel: function() {
if(jQuery.inArray(mmDialogButton.CANCEL, buttons)){
$( this ).dialog( "close" );
}
},
....
EDIT:
you can define the buttons dictionary beforehand as you like, the pass it to .dialog(:
dialog_buttons = {}
if(jQuery.inArray(mmDialogButton.CANCEL, buttons)){
dialog_buttons[Cancel] = function() {
$( this ).dialog( "close" );
}
}
if(jQuery.inArray(mmDialogButton.NEXT, buttons)){
dialog_buttons["Next"] = function() {
widget.doNext();
}
}
if(jQuery.inArray(mmDialogButton.PREVIOUS, buttons)){
dialog_buttons["Previous"] = function() {
widget.doPrevious();
}
}
if(jQuery.inArray(mmDialogButton.OK, buttons)){
dialog_buttons["Ok"] = function() {
widget.doOk();
}
}
$dialog.html(widget.getInitialHTML())
.dialog({
autoOpen: false,
title: title + ' <img id="myJquerySpinner" />',
buttons: dialog_buttons
}...