How to deal with dynamic properties in Backbone and sync to database - javascript

I have been struggling with Backbone the last few days in trying how to best approach dealing with some dynamic elements added by a user and sync those successfully with the database. I have one model and one view.
The model created is fairly straightforward, it represents a product(t-shirt) in a database and has the attributes: id, price, size, brand, colors.
The problem I am faced with is the colors attribute. The colors cannot be pre-populated by design (unfortunate as it may be) to allow for the user to enter any custom color and name it as freely as they want. In addition to the name, the user has to specify if the color is available. Clicking the Add Text button/link will have an input field and dropdown appended to the div below.
My question: What is the best way to add these multiple color properties as ONE attribute of the model?
I need to have all the colors/availability values as one property when it attempts to insert or update itself with the API as the colors property and goes into one row in the db (mysql). I believe the backend programmer has this row configured as a type of TEXT.
e.g.
{"colors": [{"blue":true},{"orange":false},{"white":false}]}
My thinking is that I need to obviously have some sort of nested JSON within the model but I can't figure out how to write this properly. Any help or something to point me in the right direction would be much appreciated.

Ok, this solution involves jQuery maybe a bit too much, but should work fine. Basically, listen to both changes of your color textboxes and select:
events: {
'change .colorText': 'setColor',
'change .colorSelect': 'setColor'
},
setColor: function() {
// here make your `color` attribute's array
var colors = [];
this.$('.colorText').each(function() {
var val, color;
// adapt the next to navigate to the corresponding select...
(val = $(this).val()) && (((color = {})[val] = $(this).next().val()) || 1) && colors.push(color);
});
this.model.set('colors', colors);
}

Related

Gravity Forms - How to Hide Some Options in a Dropdown pricing Field based on Value selected in Another Dropdown field

Gravity Form ID: 54.
I have a field where customers select their State. This is a standard dropdown field (Field ID is 11). I have another field (field ID 68) which is an "Option" field set as a dropdown. I want to be able to conditionally hide a few options/values in field 68 if the customer selects "Georgia" for their state (field 11). I read that I could achieve this through Javascript. I am very very new to JS and tried to piece together the code based on other requests, but my code is not working. None of the values are removed when I select Georgia as my state:
jQuery(document).ready(function( $ ){
jQuery("#input_54_11").on('change',function(){
var property_state = jQuery(this).val();
if (property_state == 'Georgia') {
jQuery("#choice_54_68_2").hide();
jQuery("#label_54_68_2").hide();
jQuery("#choice_54_68_5").hide();
jQuery("#label_54_68_5").hide();
}
});
});
Any help on what I am doing wrong would be greatly appreciated. As you can see above, I am trying to remove the third choice and the sixth choice in field 68 when Georgia is selected as a state. Also, I need to make sure that if a different state is selected after Georgia was first selected, that those options that were hidden reappear. Image below that also shows the labels in case that is easier to visualize.
If Georgia is the only state with special limitations on property types, you can create two versions of the Property Type field – one with the property types that are specific to Georgia and one with the property types that apply to all other states. Then you'd configured each field to show in the appropriate context (whether Georgia is selected or not).
If you have multiple states with different property types, I would recommend a more robust approach where the choices are updated dynamically based on a map of states and their available property types. I wrote a full article about this here:
https://gravitywiz.com/how-to-create-conditional-choices-with-gravity-forms/
You could do something like this in jquery:
jQuery(document).ready(function($) {
$("#input_54_11").change(function() {
var property_state = jQuery(this).val();
if (property_state == 'Georgia') { // get the selected state
jQuery("#input_54_68 option[value='Condominium']").hide();//replace with your value
}else{
jQuery("#input_54_68").children().show()
};
});
});
I actually agree with Dave and think using Populate Anything would be WAY easier though. His link explains exactly how to do it. And if you happen to have Gravity View Import Entries, you could make a spreadsheet of all the choice options and upload to the new form.

How to create a snappy User Interface with lots of local data?

I have a JSON file with 15000+ items. My JSON file has about 7MB. I'd like to display all results in a table (without pagination) and add a few checkboxes to display or hide the items under certain conditions. To simplify as much as possible, let's say I have a checkbox to display items from Paris only:
The problem is that the UI is not smooth. Clicking on the checkbox takes about one second to refresh the table. It's unacceptable.
I'm using fetch() to download JSON data and then keep it locally. When user clicks on the checkbox, here's what I did:
document.getElementById('paris-only').addEventListener('click', updateTable);
function updateTable() {
const parisOnly = document.getElementById('paris-only').checked;
items.forEach(item => item.visible = !parisOnly || item.city === 'Paris');
refreshTable();
}
function refreshTable() {
[...document.getElementById('items-table').children].forEach((tr, index) => {
tr.classList.toggle('hidden', !items[index].visible);
});
}
.hidden {
display: none;
}
I tried to play with setTimeout(_, 0), but it doesn't help much. It makes the UI freeze less, but it still takes a lot of time to refresh the table.
Is there any strategy available to make such an interface snappy? One of my ideas was to consider <canvas>, which makes drawing many elements quick, but it doesn't seem very natural for the task.
Another option would be to load data with fetch() on scroll, but I'd like to have all data loaded just once if possible.
What else should I consider?
I'd recommend using classes to signify if a given node should be shown or hidden (e.g. every node with name !== 'Paris' is in the notparis class. You can use javascript to initialize these categories (How do I add a class to a given element?) when you fetch the JSON table, and then showing/hiding can use for (tr of document.getElementsByClassName('notparis')) tr.visible = !parisOnly. If these categories overlap (i.e. you want notparis and notcoldweather), you could probably record which classes are currently visible or hidden and use document.getElementsByClassName('notparis notcoldweather') (this may be a bit more complex, but should maintain performance).
Also, changing the items directly instead of using an intermediate list might be more performant.

How can I write the code to append all of the items(XPages)?

I have many documents in Notes, all of the documents have a different form, like this picture :
(possibly like pic 1, pic 2, or pic 3)
How can I write the code in Xpages?
use the "computed field"? Or use the "input text"?
I used the "input text".But only for one item, not for all.
var doc = purchase.getDocument();
var A0 = doc.getItemValueString("DAY_A0");
if(A0 != 0){
return "Division processing";
}
If the form not only has one item, like the pics. How can I write the code to append all of the items?
I'm making the following assumptions here:
You have 10 fields in the document with numbers that might or might not be > 0
The 11th value (Total) shall be computed
You want to show one document at a time, not a list
You know how to add a data source to a page
Version 1:
Create a regular XPages form, use the wizard when adding the document data source. It now would show also the field with 0 values
Click on each ROW and change visibility property to computed (make sure you hit the row, not the cell or field) and add a visibility formula based on the field oof that row. Something like doc.DAY_A0 > 0
Add a computed field where you add the values of all 11 fields
done
Version 2:
in the page open event, get a handle on the document and compute a scoped variable that only contains the values you are interested in. Could be messy since you need a label (that is not your field name) and a value
Use a repeat control to render the values
Hope that helps

Select field populated with multiple entries after one checkbox change

I have something in my mind, but I have no idea how to get it done, so I hope I can get some advise here.
I'm working on an activity registration app (using Laravel), where every activity will be registered. Very important is that we need to record who was invited and who actually attended. I already have this part running. My issue is more on the practical side.
I use jQuery Select2 for the multiple select fields for invitees and attendees. Imagine now that there's a group of users that need to be invited or attend virtually all activities, while the invitation or attendance of others depends on the type of activity. Using Select2, I can only select users one at a time and that sucks if you need to do that for, say, 50 users for virtually every activity.
What is the best way to have a "group" that can be selected, which selection fills in all the names of those in the group in the select field? Or is there a better way to get this done?
I'm seeing something in my head, where there are checkboxes next to the select field, representing the groups. When you tick a checkbox of a group, the select field is populated with all users who are part of that group.
I have no idea ow this can be done. I looked around and every search brings up select boxes populating select boxes. None handle checkboxes.
Any advise on how to get this done?
My PHP/MySql is intermediate, Javascript/Ajax is very basic.
One strategy would be to build a control (checkbox element) that will set or toggle the selection of your group of users whenever it's clicked. Say we have the following markup:
<select class="my-big-group-select" multiple="multiple">
<!-- assorted options here -->
</select>
<label>
<input type="checkbox" class="toggle-default-group" />
Use my default big group of users
</label>
The Select2 API allows you programmatic control over the component it generates.
You can read more about it here: https://select2.github.io/examples.html#programmatic
Here's one way to leverage this knowledge using jQuery with Select2:
<script>
var groupSelect = $('.my-big-group-select').select2();
var groupToggle = $('.toggle-default-group');
var myBigGroup = ["Aaron", "Beth", "Cindy"]; // assorted option values
groupToggle.on("click", function() {
if ($(this).is(':checked')) {
groupSelect.val(myBigGroup).trigger('change');
} else {
var currentlySelected = groupSelect.val();
if (currentlySelected) {
var filteredSelections = currentlySelected.filter(function(key) {
return myBigGroup.indexOf(key) < 0;
});
groupSelect.val(filteredSelections).trigger('change');
}
}
});
</script>
Here's a CodePen that shows it all in action: http://codepen.io/anon/pen/qNQKOd
Of course you can build on this to make additional enhancements (the ability to select multiple groups, for example).
As an alternative, you may consider other code libraries like Bootstrap Multiselect: https://davidstutz.github.io/bootstrap-multiselect/
Hope this points you in the right direction!

How to update ZK Grid values from jQuery

I have three Tabs and in each tab, I have a Grid.
The data for each Grid is coming from a database, so I am using rowRenderer to populate the Grids. The following code is common for all three Grids:
<grid id="myGrid1" width="950px" sizedByContent="true" rowRenderer="com.example.renderer.MyRowRenderer">
The rows are constructed from Doublebox objects. The data is populated successfully.
The Problem:
I need to handle multiple-cell editing on the client side. The editing is done via mouse-clicking on a particular cell and entering a value.
As example let's say that the user edits first cell on the first row and the value should be
propagated to all other cells on the same row and in all three Grids (so also the two Grids which the user currently does not see, because they are in tabpanes).
I am using jQuery to do this value propagation and it works OK.
I am passing the jQuery as follows:
doublebox.setWidgetListener(Events.ON_CHANGING, jQuerySelectors);
doublebox.setWidgetListener(Events.ON_CHANGE, jQuerySelectors);
This makes it possible to change the value in 1 cell and the change is instantly (visually) seen in all other cells filtered by jQuery selectors.
The problem is that the value is visually distributed to all the cells, but when I try to save the Grid data back to the database, the background values are the old ones.
I am assuming that ZK-Grid component is not aware that jQuery changed all the cell values. Nevertheless if I manually click on a cell that already has the NEW value (enter/leave/change focus) when I save the grid the NEW value is correct in that particular cell. Maybe that's a hint how can I resolve this.
Code of how I extract the Grid values:
Grid tGrid = (Grid) event.getTarget().getFellow("myGrid1");
ListModel model = tGrid.getModel();
MyCustomRow tRow = (MyCustomRow)model.getElementAt(i);
The model for my Grid is a List of MyCustomRow:
myGrid1.setModel(new ListModelList(List<MyCustomRow> populatedList));
I have a couple of assumptions, but whatever I have tried, hasn't worked. I have in mind that jQuery events and ZK-Events are different and probably isolated in different contexts. (Although I have tried to fire events from jQuery and so on..)
Do you have any suggestions? As a whole is my approach correct or there's another way to do this? Thanks for your time in advance!
Your problem is exactly what you are expecting.
Zk has it's own event system and do not care about your jq,
cos it's jq and zk don't observ the DOM.
The ways to solve your problem.
Use the "ZK-Way":
Simply listen at server-side and chage things there.
I am not sure if not selected Tabs
are updateable, but I am sure you could update the Grid
components on the select event of the Tab.
Fire an zk-event your self:
All you need to know, is written in the zk doc.
Basically, you collect your data at client side, send
an Event to the server via zAu.send() extract the
data from the json object at serverside and update your Grids
I would prefer the first one, cos it's less work and there should not be
a notable difference in traffic.
I post the solution we came up with:
This is the javascript attached to each Doublebox in the Z-Grid
//getting the value of the clicked cell
var currVal = jq(this).val();
//getting the next cell (on the right of the clicked cell)
objCells = jq(this).parents('td').next().find('.z-doublebox');
// if there's a next cell (returned array has length) - set the value and
// fire ZK onChange Event
if (objCells.length) {
zk.Widget.$(jq(objCells).attr('id')).setValue(currVal);
zk.Widget.$(jq(objCells).attr('id')).fireOnChange();
} else { //otherwise we assume this is the last cell of the current tab
//So we get the current row, because we want to edit the cells in the same row in the next tabs
var currRow = jq(this).parents('tr').prevAll().length;
//finding the next cell, on the same row in the hidden tab and applying the same logic
objCellsHiddenTabs = jq(this).parents('.z-tabpanel').next().find('.z-row:eq(' + currRow + ')').find('.z-doublebox');
if (objCellsHiddenTabs.length) {
zk.Widget.$(jq(objCellsHiddenTabs).attr('id')).setValue(currVal);
zk.Widget.$(jq(objCellsHiddenTabs).attr('id')).fireOnChange();
}
}
The java code in the RowRenderer class looks something like this:
...
if (someBean != null) {
binder.bindBean("tBean", someBean);
Doublebox box = new Doublebox();
setDefaultStyle(box);
row.appendChild(box);
binder.addBinding(box, "value", "tBean.someSetter");
...
private void setDefaultStyle(Doublebox box) {
box.setFormat("#.00");
box.setConstraint("no negative,no empty");
box.setWidth("50px");
String customJS = ""; //the JS above
//this is used to visually see that you're editing multiple cells at once
String customJSNoFireOnChange = "jq(this).parents('td').nextAll().find('.z-doublebox').val(jq(this).val());";
box.setWidgetListener(Events.ON_CHANGING, customJSNoFireOnChange);
box.setWidgetListener(Events.ON_CHANGE, customJS);
}
What is interesting to notice is that ZK optimizes this fireOnChange Events and send only 1 ajax request to the server containing the updates to the necessary cells.

Categories

Resources