ExtJS - Get array on DOM nodes in Grid, highlight()? - javascript

Here's what I'm trying to accomplish. I have a grid with entries that a user can "batch update", that is a user can select a single or multiple entries from the grid, select values from a form above the grid that they want to apply to all entries, and then submit.
What I'd like to accomplish is a highlight() done on all the changes rows. The problem I'm having is I don't know how to run a highlight() on all of the changes values at once, so I've been doing it individually. I might just be running through the loop wrong. Here's what I'm doing to update the values.
// for every property we have in our batchUpdateValues
for (var propertyName in batchUpdateValues) {
// change the selected banners attributes to match
for (var i = 0 ; i < bannersToUpdate.length ; i++)
{
// if they've selected "Name", we only want to append, not replace"
var oldName = bannersToUpdate[i].get('bannerName');
if (propertyName == 'bannerName') {
bannersToUpdate[i].set(propertyName, oldName + ' ' + batchUpdateValues['bannerName']);
} else {
bannersToUpdate[i].set(propertyName, batchUpdateValues[propertyName]);
}
var changedRowId = this.getStore().indexOf(updatedBanners[i]);
var changedRow = this.getView().getRow(changedRowId);
Ext.get(changedRow).highlight();
}
}
What's happening now is if the user selects 4 "attributes" to update form the form the highlight gets run 4 times, so I'd need to put that code outside the loop. How would I grab all of the DOM attributes for each row and then run a highlight on them()?

My first suggestion is to make sure you understand the SelectionModel. It's described in the documentation. I'd link you but I'm not sure which version you're using. Actually, what version of Ext JS are you using? The answer to this question might be different in 3.x vs. 4.x.
I'd be happy to answer in more detail but I'll need you to clarify with an example. Could you build a small table with some dummy data and then explain when you're talking about rows/columns in the model?

Related

JQuery & Javascript: Intermittant mis-matching of clicked div and returned div?

Thanks for giving this a look. I'll start with a quick image. Clicking on any of the red-boxed search results seems to return the <div> for the item directly above it.
Here I clicked on 1613 CAROUSEL CIR, but the event returned the id/content for the item representing 1612..
Sometimes it's even weirder, for example, every item following 1420 might point back to 1420. So it's not always a conflict with a <div> and it's immediate neighbor, although that's usually the case.
I've been unable to find any definite pattern in this behavior. Sometimes it's just one or two items in the list; sometimes most of the list is affected, with "a good portion" of results pointing to one particular div.
There's only one true consistency--typically the first several items work as expected, and short lists will be 100% correct. But really long lists (50+) are not necessarily worse than semi-long lists (20+).. :/
The code building the search results iterates over JSON data retrieved by a JQuery $.ajax() call, and this is the relevant code building the visible search results:
if( result.d.length > 0 )
{
var i=0;
for(i; i<result.d.length; i++)
{
// ..there's a bunch of irrelevant code here to set the map bounds..
// ..then I build the HTML using JQuery like this
//
var date = new Date();
var divID = "searchItemDiv" + date.getTime().toString();
var $searchItemDiv = $( "<div id='" + divID + "' class='searchItemDiv'>"+result.d[i].Description+"</div>" );
$searchItemDiv.data('itemData', result.d[i]);
$searchItemDiv.bind('click', onSearchItemClick);
$( "#searchResults" ).append($searchItemDiv);
}
}
While I don't suspect the event handler is the issue, the relevant code there looks like this:
function onSearchItemClick(event)
{
if( event.target.id.toString() !== '' )
{
// I clicked 1613, but event returned DIV with text of "1612"??
//
var item = $('#'+event.target.id.toString()).data('itemData');
alert( event.target.id.toString()+"\n"+
$('#'+event.target.id.toString()).text() );
// ..more irrelevant stuff to show a popup of property data..
}
}
FireFox, Chrome, and IE all demonstrate the same behavior, so it's not browser-specific.
I'm relatively sure this is not the product of a race condition during the render phase, but I'm not comfortable-enough with JavaScript to know that for certain.
I'm pretty baffled by this. FWIW, I'm a former Flex & C# developer and relatively new to JavaScript/JQuery development, so there may be a gotcha related JavaScript contexts and/or JQuery that I'm stepping into.
I would say, instead of binding the click function within a for-loop, just select all of the searchItemDiv's after the for-loop binds the data to them, and register a click function on all of them at once. You don't need a separate line to define variable i, just do it in the for statement. I also wouldn't try to generate random IDs with new Dates, that just seems unnecessary. Registering all click functionality at once will also make your click handler much simpler:
if( result.d.length > 0 )
{
for(var i = 0; i<result.d.length; i++)
{
// ..there's a bunch of irrelevant code here to set the map bounds..
// ..then I build the HTML using JQuery like this
// select the i'th searchItemDiv
$searchItemDiv = $($('.searchItemDiv')[i])
// give it the data
$searchItemDiv.data('itemData', result.d[i]);
$( "#searchResults" ).append($searchItemDiv);
}
// then register all the click handlers at once, very simple
$('.searchItemDiv').bind('click', function() {
var item = $(this);
alert(item.text());
});
}
--EDIT--
also, do the searchItemDivs already exist or are you trying to create them?
if you're trying to create them, you might want this in the for-loop instead:
for(var i = 0; i<result.d.length; i++)
{
// ..there's a bunch of irrelevant code here to set the map bounds..
// ..then I build the HTML using JQuery like this
// create a searchItemDiv
$searchItemDiv = $('<div class="searchItemDiv"></div>')
// give it the data
$searchItemDiv.data('itemData', result.d[i]);
$( "#searchResults" ).append($searchItemDiv);
}
I'm guessing that is what you want to do.
I think your problem depends on your searchItemDiv id.
Using the date doesn't ensure ids are unique so when you retrieve the object by id it will return an element (probably the first) with the same id.
Make sure to assign unique id on your elements.

Dropdown Menu using the 'storeLocator.Feature' in the Store Locator Library for Maps API

Is there any way of using a Dropdown Menu as opposed to the checkbox's that are used in the examples of the Store Locator Library for Maps API. The checkbox is a 'storeLocator.Feature' item.
Essentially I want the user to be able to select an item from the dropdown list and this instantly change the markers on the map.
I am very new to Javascript coding but experienced in CSS, HTML and other computer languages. I have followed the examples in the link fairly closely so you can assume my own code looks the same. –
Here is the section of code i think i have to edit:
DataSource.prototype.parse_ = function(csv) {
var stores = [];
var rows = csv.split('\n');
var headings = this.parseRow_(rows[0]);
for (var i = 1, row; row = rows[i]; i++) {
row = this.toObject_(headings, this.parseRow_(row));
var features = new storeLocator.FeatureSet;
features.add(this.FEATURES_.getById('Cafe-' + row.Cafe));
features.add(this.FEATURES_.getById('Wheelchair-' + row.Wheelchair));
features.add(this.FEATURES_.getById('Audio-' + row.Audio));
var position = new google.maps.LatLng(row.Ycoord, row.Xcoord);
var shop = this.join_([row.Shp_num_an, row.Shp_centre], ', ');
var locality = this.join_([row.Locality, row.Postcode], ', ');
var store = new storeLocator.Store(row.uuid, position, features, {
title: row.Fcilty_nam,
address: this.join_([shop, row.Street_add, locality], '<br>'),
hours: row.Hrs_of_bus
});
stores.push(store);
}
return stores;
};
Thanks.
you need to follow these steps:
set the featureFilter-option of the panel to false
(this will prevent the library from creating the checkboxes)
create a variable where you store all features for later use:
var features=view.getFeatures().asList();
this returns an array with all features
create the select-element
populate the select-element with the needed option-elements
iterate over the features-array created above and append an option for every item to the select .
The text to display inside the option you get by calling the getDisplayName()-method of the item.
add a change-handler to the select with the following callback:
function(){
view.set('featureFilter',
new storeLocator.FeatureSet(features[this.selectedIndex]));
view.refreshView();}
(where view is the storeLocator.View and features the array created in step#2)
5. put the select to the desired place inside the document
Hope i'm allowed to comment here as i found this question very useful for my implementation of store locator.
Dr Molle's solution in the JS fiddle is excellent however i've just noticed that the 'directions' functionality of the map no longer works. Could this easily be rectified? thanks
edit: easier than i thought. In the fiddle "featureFilter:" is set to 'false'. A div with the class="feature-filter" needs to be present in the code for the directions to appear, setting the value to 'true' shows the div (and checkboxes) so that directions work. Checkboxes were hidden in the stylesheet..
.storelocator-panel .feature-filter {
/*overflow: hidden;*/ display:none
}
This may be useful to someone

Cloned row requesting same function [duplicate]

This question already exists:
Closed 10 years ago.
Possible Duplicate:
Call same function by a cloned list row
I am trying to make a simple calculation to work.
I have the following running:
http://jsfiddle.net/vSyK6/41/
Basically, the way it works now is this:
When you select an option on the drop down list it will display the content based on the option selected. Then when you select the same option again it will add, basically clone the same row.
Now, when the second option is selected "Option2" it will display an empty textbox. When you enter a number it will or should call the a function where we make a basic calculation. The function is already in the script.
However, when we have two empty textboxes it should call the same calculation function but calculate seperately and puts it in a different div. The div# where we display the amount is a called "amount"
Basically, it should work like this:
First Empty textbox -> 100 -> 100 * 22.38 = display result in div#1
Second Empty textbox -> 230 -> 230 * 22.38 = display in div#2
any idea on how to accomplish that ?
When cloning elements the id is cloned as well. It is best practice to create a new ID for the cloned elements, which will also help in accomplishing what you want. The same goes for the name attribute as well.
With a few modification to your code, http://jsfiddle.net/dNQVQ/3/, I was able to get what you were after. Let me first say that this might not be the ideal way to go, but it is a start. Like I said earlier the key is going to be setting unique ids for the cloned elements. What I did in this example was use a index as part of the list element id that is cloned with a matching index in an 'amount' div. This way when an input is updated the index is retrieved and then used to update the appropriate div. Additionally, I moved the function that did the calculation and updates to an anonymous function in the settimeout call. This makes it easy to use a reference to the updated input in the function call.
Joining the party quite late here :) Here is one vernon: http://jsfiddle.net/KVPwm/
ALso if its assignment bruv, put an assignment homework tag!
People around SO community are awesome folks so be truthful, guys will help man!
Use .on instead of live - recommendation. i.e. upgrade your JQ source if keen read this - What's wrong with the jQuery live method?
you have 2 document.ready functions also I chained few things for you.
Also think of using isNan check as well.
Rest you can read the code and play around a bit to make it more concise.
I have added 2 divs and using the id number to populate the stuff accordingly.
This should fit the cause :)
code
$("document").ready(function() {
/////////////////////////////////CALUCATIONS/////////////////////////////////
//setup before functions
var typingTimer; //timer identifier
var doneTypingInterval = 0; //time in ms, 5 second for example
$('input[name=Input2], input[name=Input1]').live('keyup', function() {
var str = $(this).prop("id");
var pattern = /[0-9]+/g;
var matches = str.match(pattern);
amount = parseFloat($(this).val()) * 22.38;
typingTimer = setTimeout(doneTyping(matches), doneTypingInterval);
});
$('#Input2').keydown(function() {
clearTimeout(typingTimer);
});
function doneTyping(matches) {
$('#amount'+matches).text(amount.toFixed(2) + " lbs");
}
$("#List-Option1,#List-Option2").hide();
$('#category').change(function() {
var str = $('#category').val();
if (str == 'Option1') {
var option1 = $("#List-Option1:first").clone().show();
$('#box li:last').after(option1);
}
if (str == 'Option2') {
var option2 = $("#List-Option2:first").clone().show();
$('#box li:last').after(option2);
}
});
});​

Knowing which column is being updated

I am trying to get handsontable to give me which column is being updated, but have not been able to find a proper solution. I understand they are using a textarea to get the input and then putting the values into a table, but I just cannot figure out how to find out which column is being update.
Any help would be appreciated.
Thanks
This method will tell you what row/column is selected:
$('#example1grid').handsontable('getSelected')
This will be return the same coordinates as the currently edited cell, except for cases when there are multiple cells selected (but even then the currenyly edited cell is always within selected cells).
I am thinking about creating a new method getCurrent or callback onBeginEditing to return currently edited cell. Which would be better for you? I think the callback would be better.
onChange: function (data) {
for (i in data) {
if(data[i][2] != data[i][3]) {
var column = $('#dataTableLoc td:nth-child(' + (data[i][1] + 1) + ')')[0].innerText;
}
}
}
This is obviously far from elegant. It will conflict with any extensions like the "removeRow" example in buttons.html but obviously can be adjusted accordingly. Its necessary when pulling data from an SQL table and trying to update using a query.

In jQuery, how to efficiently add lots of elements?

I currently have a sketch for a truthtable generator. While it works fine, it is rather slow. Each combination of boolean values I have added to a <table> using jQuery. For each value, a <td> element is created by jQuery and then added to the <table>. Moreover, I'm using jQuery UI for a nice looking buttonset instead of radio buttons.
In my posted code extract, table is an array containing each boolean combination. Perhaps my code is a little inscrutable but what it basically comes down to is that with 4 boolean variables (16 possibilities), 96 <td> elements are created with classes added and data attributes set. In the second part, three groups of three radio buttons are created and converted into a jQuery UI buttonset.
Using a timer I figured out that it takes approximately 0.4 seconds before everything is filled up. Not that big of a deal, but it is certainly noticeable and does not have a positive effect on the user as each time he enters a different boolean formula it takes half a second to load.
$table = $('#table');
$.each(table, function(k, v) {
$tr = $('<tr>').addClass('res').data('number', k);
$.each(v[0], function(k2, v2) {
$td = $('<td>').text(v2).addClass(v2 ? 'green notresult' : 'red notresult');
for(var i = 0; i < 4; i++) {
$td.data(i, i === k2);
}
$tr.append($td);
});
$tr.append($('<td>').addClass('spacing'));
$table.append(
$tr.append(
$('<td>').text(v[1]).addClass(v[1] ? 'green result' : 'red result')
)
);
});
// ... here is some code that's not slowing down
$radiobuttonsdiv = $('#radiobuttonsdiv');
for(var i = 0; i < 4; i++) {
var $radiobase = $('<input>').attr('type', 'radio')
.attr('name', 'a'+i)
.click(handleChange);
// .label() is a custom function of mine which adds a label to a radio button
var $radioboth = $radiobase.clone().val('both').label();
var $radiotrue = $radiobase.clone().val('true').label();
var $radiofalse = $radiobase.clone().val('false').label();
var $td1 = $('<td>').addClass('varname').html(i);
var $td2 = $('<td>').attr('id', i);
$td2.append($radioboth, $radiotrue, $radiofalse).buttonset();
var $tr = $('<tr>').append($td1, $td2);
$radiobuttonsdiv.append($tr);
}
My questions are:
How could table-filling using jQuery be optimized? Or is a table perhaps not the best solution in this scenario?
Is it perhaps possible to suspend drawing, since that might be slowing everything down?
Try to avoid using .append in a loop, especially if you're adding a lot of elements. This is always a performance killer.
A better option is to build up a string with the markup and do a single (or as few as possible) .append when your loop is finished.
I see that you're using .data, which makes things a bit more complicated, but another option is to use the metadata plugin to attach structured markup to existing tags.
To defer rendering, you could try creating a new table without adding it to the DOM like:
var myDisconnectedTable = $('<table></table>')
Then adding your rows to that table:
myDisconnectedTable.append(...)
Then append your table to the div you want it in:
$('#idOfMyDiv').append(myDisconnectedTable)
I don't know that it will help, but it's worth a shot.

Categories

Resources