Create a Dojo grid and Add Dialog from Data Model - javascript

I am developing an app where users can perform CRUD operations on multiple data models (aka. DB tables). I am using Dojo and I am quite happy with the dojox.grid module. But users also need to add records, so there has to be an Add Dialog for each table.
Is there a way/module that generates a Dojo grid and an Add Dialog given only the data structure of the model? Sort of like the structure parameter of dojox.grid, so that both the grid and the add Dialog have the same data types, default values, contraints etc.
Of course I could write a custom widget that would just do that but I am looking for something existing here.

The answer is, no there is no such module. You'd need to build a derived dialog.
Lets see whats needed;
The current grid
the grid layout (celltypes)
names and labels (structure)
Assuming there is one 'Add contents' button defined pr-grid and that this button 'knows' the ID of the said grid, its onClick function should fire up a form in dialog.
While there are dijit.form Widgets there's also a range of predefined cellTypes, residing under dojox/grid/cells/_base.js. Lets make a map where type and widget is 1to1:
var map = [{
type: 'dojox.grid.cells.Cell',
dijit: 'dijit.form.TextBox'},
{
type: 'dojox.grid.cells.Bool',
dijit: 'dijit.form.CheckBox'},
{
type: 'dojox.grid.cells.Select',
dijit: 'dijit.form.Select'},
{
type: 'dojox.grid.cells.DateTextBox',
dijit: 'dijit.form.DateTextBox'}
];
In our addContents function we will make use of the 'editable' functionality in the dojox.grid.DataGrid. When we know there's a such - there is certainly also a function pr-cell that generates the DOM. This is the formatEditing function which is present in any cellType.
// for instance
dojox.grid.cells.Select.prototype.formatEditing( /* value */ "", /* row */ -1);
Only thing thats needed is to construct the contents which should be shown in the dialog - following uses the above mentioned functionality and provides dijit suitable markup for presentation in a dijit.Dialog.
function addContents(gridId) {
var grid = dijit.byId(gridId);
var contents = ['<form action="MySubmitUrl" data-dojo-type="dijit.form.Form"><table>'];
dojo.forEach(grid.layout.cells, function(cell, idx) {
var szHtml = cell.formatEditing("", -1);
var dijitType = map.filter(function(e) {
return e.type == cell.declaredClass;
})[0].dijit;
var name = grid.structure[0][idx].field;
var label = grid.structure[0][idx].name;
var elementMod = ' data-dojo-type="' + dijitType + '" id="' + name + '" name="' + name + '" ';
contents.push('<tr><td>');
contents.push('<label for="' + name + '">' + label + ': </label>');
contents.push('</td><td>');
contents.push(szHtml.replace(/^([^\ ]*)/, "$1" + elementMod));
contents.push('</td></tr>');
});
contents.push('</table></form>');
var dialog = new dijit.Dialog({
content: contents.join("")
});
dialog.show();
}
The contents is easy style-able and should also supply a submit/cancel button but im certain you get the idea. Running sample
Let me know how it runs (havent tested combobox / datetime types)

Related

Need help to add javascript array contents to an existing piece of HTML code

My front-end skills are fairly limited. I have a trained language model which generates 'tweets'.
I have this javascript function which currently displays the tweets as a paragraph.
function addResponse(msg) {
document.getElementById("results").textContent = ""
var para = document.createElement("div");
var s = "<div class='center' id='gpt2'> <b> Here what our BOT has to say... </b> </br></br>"
i = 1
for (var key in msg){
var value = msg[key];
console.log(value);
s = s + i + ") " + " <b>" + value + "</b> </br></br>"
i = i + 1
}
para.innerHTML = s + "</div>";
document.getElementById('append').appendChild(para);
}
Instead of displaying in a paragraph, I want to display as a proper tweet.
Here is a tailwind CSS implementation to create the UI of the tweet: https://codepen.io/webcrunchblog/pen/xedQVv
Currently this displays a fixed string "Starhopper". What I want to do is, loop through my array object 'msg' and display all the tweets with the proper UI .
Currently the addResponse() is called as part of ajax callback for successful response. From there how can I include the tailwind CSS code so that I can display every array element in its own tweet UI?
Hope the question is clear.
EDIT: Created this codepen if anyone wants to try it out: https://codepen.io/nikhilno1/pen/RwPBWvb
In the output, there is a tweet and three sentences. I want 3 tweets to be created for each of the sentence.
I've updated a bit of your code here: https://codepen.io/rxna/pen/OJVwMOm
The idea is to:
Clone the tweet element, have added a custom class for that:
var articleNode = document.querySelector(".tweet-body");
var clone = articleNode.cloneNode(true);
Update the text within each element:
var title = clone.querySelector(".tweet-text");
title.innerText = value;
And lastly append within the DOM:
document.getElementById("append").appendChild(clone);
It's not perfect but hopefully you'd get the idea.

How to control the 10 records previewed in a lookup control?

I am working with activities and the fields, to, from, etc.
We have created custom views dynamically in order to make the selection easier. That is fine
My problem is... when you push the icon to search contacts... Is it possible add and order a custom list for the previewed 10 records?
To avoid the user clicking on the "Look up More records", select the custom view and add the "TO" record?
Custom views always gives the power for users to switch & select the records. If you cannot solve it by user training, then implement some form save (or pre-update plugin) validations to iterate through the party list & alert them when things are not in place.
Otherwise - I used to do this addPreSearch and addCustomFilter technique all the time. Read more
function FilterPartyList() {
var Regarding = Xrm.Page.getAttribute("regardingobjectid").getValue();
//checking if regarding fields is empty before we apply the filter
if (Regarding != null) {
Xrm.Page.getControl("requiredattendees").addPreSearch(Filter);
}
}
function Filter() {
var RegardingValue = Xrm.Page.getAttribute("regardingobjectid").getValue();
//if Regarding has a value, proceed
if (RegardingValue != null) {
//used to retrieve Name of the Account held in the Regarding field
var RegardingTextValue = RegardingValue[0].name;
//GUID used in filter
var RegardingID = RegardingValue[0].id;
var plist_filter = "<filter type='and'>" + "<condition attribute='parentcustomerid' operator='eq' name='" + RegardingTextValue + "' value='" + RegardingID + "' />" + "</filter>";
Xrm.Page.getControl("optionalattendees").addCustomFilter(plist_filter, "contact");
}
}

Issues with search bar filter, using JS/JQuery in laravel blade template

I have a blade template with a search bar, which has no submit button and is used for filtering. However, I can't seem to get it to filter appropriately, as the page was originally using angular (which has been removed completely).
My page displays all of my products using foreach loops and displays the info from variables in my page controller (pulling everything from the database and storing as variables). Anyway, everything displays fine but I need help getting this to filter properly.
Basically, if a term entered in the search bar is anywhere in the JSON object gathered by the controller, then I want it to only display those objects. I may even need another foreach loop.
Here's the html/blade code:
<!--Search bar div-->
<div class="uk-width-5-10">
<div class="md-input-wrapper search-form">
<form id="searchProducts">
<input type="text" class="md-input label-fixed" name="srch-term" id="srch-term" autofocus placeholder="Search Products"/>
<span class="md-input-bar"></span>
</form>
</div>
<!--foreach loops around the wrapper that shows products, for reference-->
#foreach ($orderFormData->pgroups as $pgroup)
#foreach ($pgroup->image_names as $image_name)
#foreach ($pgroup->pskus as $psku)
Javascript for the search (see the variable for the JSON object, that's what I need to search within)
<script>
var orderFormData = <?php echo json_encode ($tempdata);?>;
</script>
<script>
var orderData = orderFormData // default value
var search = function (e) {
var term = e.currentTarget.value
orderData = Object.entries(orderFormData).reduce(function (data, entry) {
if (entry[0].match(term) || entry[1].match(term)) {
data[entry[0]] = entry[1]
}
return data
}, {})
console.log(orderData)
}
document.querySelector('#srch-term').addEventListener('keyup', search)
</script>
Is there a better way I should be doing this? I may even need to do a foreach loop around the search bar
It kind of sounds like you're looking for an auto complete. Have you looked at the jquery-ui-autocomplete library? It's pretty easy to implement, and might add more functionality more easily than writing loops yourself.
https://jqueryui.com/autocomplete/
I'll get into why I named the function below, but here's my implementation:
monkeyPatchAutocomplete();
$("#your_searchbox_selector").autocomplete({
source: // http://Your_Search_URL_endpoint_here,
delay: 500, // prevents search from running on *every* keystroke
minLength: 1, // default is 2, change or remove as you like
// open page after selecting (with enter key).
select: function( event, ui )
{
var qval = ui.item.id // this pulls whatever field you're looking for in your JSON that you want to use to direct your user to the new page, in my case "id";
var url = 'http://whereever_you_want_your_user_to_go?';
window.location = url + qval;
}
});
For my implementation, I wanted to color code the results in my autocomplete list with active and inactive entries, so my search controller JSON result includes 3 fields:
'value' => $searchable_values, 'id' => $id_mapping_of_whatever, 'class' => $css_classes_to_use
My search controller plugs in emails, names, and phone numbers to the value field, which is searchable, then maps an id, and plugs in css classes that I use to change the text color of the results through a monkeypatch on jQuery's autocomplete:
function monkeyPatchAutocomplete()
{
$.ui.autocomplete.prototype._renderItem = function( ul, item)
{
var re = new RegExp(this.term, 'i');
var t = item.label.replace(re,"<span class='autocomplete-span'>" + this.term + "</span>");
return $( "<li></li>" )
.data( "item.autocomplete", item )
.append( "<a class='text-" + item.class + "'>" + t + "</a>" )
.appendTo( ul )
};
};
If you're interested in formatting your results, check out dev.e.loper's answer to: How can I custom-format the Autocomplete plug-in results?.

How to Add a Drop Down List in a Kendo UI Grid

Using Kendo UI and a Row Template, I have a grid started like the following:
http://jsfiddle.net/xF4CK/
I'm wanting to alter the Actions column to contain a drop down list populated by the actions object. The actions object contains display text and a relative url path like the following example:
var actions = [
{ name: "edit", url: "reports/report/1" },
{ name: "delete", url: "reports/delete/1" }
];
This actions object is on each row of the grid and may vary per row/user/etc. The intended usage would be a user selects the drop down list and then chooses one of the options. On choosing the option the url value is posted.
I'm not sure where to begin, or if it is possible in the Row Template. Any help is greatly appreciated.
I was able to get it figured out. In the row template I am calling a js function and returning html markup for the list. Then setting the .kendoDropDownList on all items based on a class attribute. I have updated the jsfiddle here but it doesn't seem to work in jsfiddle. It is working when I test in IE10 and Chrome on my dev machine.
Here's the relevant code changes:
In the rowTemplate, changed
#: actions #
to
#= renderDropDown(actions) #
This "=" displays the literal text which renders the html as html whereas the ":" encodes the html.
The renderDropDown function:
function renderDropDown(actions) {
var dropDownList = "<select class=\"insight-dropdown\">";
dropDownList = dropDownList + "<option value=\"default\" disable=\"disabled\">...</option>";
for (var i = 0; i < actions.length; i++) {
dropDownList = dropDownList + "<option value=\"" + actions[i].url + "\">" + actions[i].name + "</option>";
}
dropDownList = dropDownList + "</select>";
return dropDownList;
}
To the dataBound event of the grid, I added this function to turn the html into a drop down list:
// Set the drop down lists
$(".insight-dropdown").kendoDropDownList({
select: onDDLSelect
});
To handle the selection of an action:
function onDDLSelect(e) {
var dataItem = this.dataItem(e.item.index());
alert(dataItem.value);
}

jQuery/JavaScript: Avoid unique ID's for each row in a table?

I'm not sure if I'm doing this the right way. I have table which I fill with rows that each represent a song in a playlist. Right now, I assign a unique ID per row, and also assign som jQuery.data() to each ID.
html += '\
<tr id="track-' + i + '" class="tracks-row"> \
<td class="track"><a id="play-'+ i +'" class="play"></a><a id="play2-' + i + '">' + song.song_track + '<span class="mix-style">' + song_mix + '</span></a></td> \
<td class="artist">' + song.song_artist + '</td> \
<td class="favourites-holder"><a id="favourite-' + i + '" class="favourites"></a></td> \
' + delete_holder + ' \
</tr> \
';
So as you can see, each row has an ID like track-1, track-2 etc.
Is there another way to populate a playlist like this without assigning unique ID's to each track, or is this how it's supposed to be done? Each track has some properties like this:
$("#track-" + i).data("song_id", song.song_id);
$("#track-" + i).data("song_artist", song.song_artist);
$("#track-" + i).data("song_track", song.song_track);
$("#track-" + i).data("song_mix", song.song_mix);
$("#track-" + i).data("ps_id", song.ps_id);
... and also .click events for each track, which allows the user to play, sort, drag etc... It just feels like I'm doing it wrong :)?
You could store a reference to each generated row in your loop (assuming html only contains the HTML for a single row):
var row = $(html).appendTo("#table");
var data = row.data();
data["song_id"] = song.song_id;
data["song_artist"] = song.song_artist;
data["song_track"] = song.song_track;
data["song_mix"] = song.song_mix;
data["ps_id"] = song.ps_id;
row.click(function(){...});
It is not bad to have an ID for an element. But is definitely faster to make use of a reference if you have one and not use jQuery's selector engine over and over again.
Also if you attach the same click handler to every row, it is probably better to just attach one to the table and delegate it, e.g.
$('#table').delegate('tr', 'click', function(){...});
Unique id's makes sense or use the Metadata plugin to store all the extra data related to each row. http://plugins.jquery.com/project/metadata
It will store the data like:
<li class='someclass' data="{some:'random', json: 'data'}">...</li>
And you can query this like this:
var data = $('li.someclass').metadata();
if ( data.some && data.some == 'data' )
alert('It Worked!');
Whether the tr needs a unique id or simply a generic class is going to depend a lot on what you intend to do with either javascript (for targeting the rows) or css (also for targeting the rows). If you need to specifically target one row for styling or script effects, a unique id can be an effective way of doing it. If not, then it may be extra "mark-up" that is unnecessary.
In any case, if you do use id's, do make sure they are unique :-)
May be something like this with jquery:
var songs = function(songList){
this.songs = songlist;
this.init();
}
$.extend(songs.prototype, {
init: function(){
var self = this;
var table = $('#myTableID');
for(var i = 0; i < this.songs.length; i++){
var song = this.songs[i];
var songData = $('<tr><td class="track">'+song.track+'</td><td class="artist">'+song.artist + '</td></tr>');
table.append(songData);
songData.find('td.track:first')click(function){
self.SongClick(song.track);
});
//add other events here
}
}
},
SongClick : function(track){
//add here you click event
},
otherEvent : function(track){
//add otherEvent code
}
});
Like this you can create your javascript object and attach events to the dom elements directly as you parse them. You will not need any id's.
This approach will create a js object with its constructor
so you can say
var so = new songs(mySongList)
when it initializes it will retrieve a table with an id of myTableID and foreach song in the list, it will attach elements to it, and will attach the events directly to those elements.

Categories

Resources