Angular Sorting and counting, Dragula - javascript

I have the following scenario:
A JSON object array gets fetched with angular ajax and displayed as list with ng-repeat.
The list gets sorted by object property "index", which is set as default input value of the respective list item.
The user can change the input values.
On press of a button, the list gets redrawn, sorted by the updated input values.
Now there should be a counter, ++ whenever a list item changes position.
I so far managed to count all list items with updated values.
How do I register position changes for the other list items that change position?
For example: #3 changes position to #1, then #1 and #2 also change position.
Second, using Dragula, the list items are now draggable.
How can I resort the list after list items were dragged?
I also tired Angular Dragula without success.
here is my code on github.
Thank you for your help!

I had a similar issue. You need a way of getting the DOM indexing and updating the JavaScript object to match. I looped through the DOM elements, got their index values, found the corresponding item in the data object and then set the index value in the object to that of the DOM index value. Hope this example helps someone.
var updateIndexes = function() {
// this gets the index of any DOM element, like jQuery index()
function getIndex(el) {
for (var i = 0; el = el.previousElementSibling; i++);
return i;
}
// loop through the list DOM elements
for (var i = 0; i < dataArray.length; i++) {
var dataId = dataArray[i].id;
var domIndex = getIndex(document.getElementById(dataId));
dataArray[i].index= domIndex;
}
};

Related

Batch adding items to Selectize.js control stalling the browser completely

i am using selectize.js to display a multiselect dropdown list witch zipcodes and cities. Its functioning well when searching and adding one item at a time, with the autocomplete search, but when im trying to add a batch of zipcodes from a multidimensional array, it totally frezzes the page, and takes more than 20 seconds to complete with insertion of a batch of 100 zip codes or so.
The following is my two add and remove functions, using data from my multidimensional array of zipcodes, with a parent region id. The events are fired via a dropdown of regions with the value of the first dimension in the region_relations array.
var control = new Array();
control.push($select[0].selectize);
control.push($select[1].selectize);
function addItemToselect(key_index, region){
var index;
for (index = 0; index < region_relations[region].length; ++index) {
control[key_index].addItem(region_relations[region][index]);
}
}
function removeItemToselect(key_index, region){
var index;
for (index = 0; index < region_relations[region].length; ++index) {
control[key_index].removeItem(region_relations[region][index]);
}
}
I can't seem to find a solution to this problem - i thought i could maybe use jQuery to set the original options checked and call the refreshItems() function in selectize, but it seems like selectize is actually emptying the original , and so options will only be present in this element if an item has been selected using selectize - the script itself includes a addItems() function, but it basically does the same as above, i hoped the selectize addItem had a efficient way of batch adding items, but as it seems right now, i might be out of luck, and we are talking a max of 100 items to add or remove at a time....?
Do you have any suggestions?
My problem can be demonstrated "real life" on this page: http://onlineboligsalg.dk/soeg-bolig/ , the controls are found on the left.
thanks in advance for your help

How to remove searched entry from array in AngularJS

I am creating a angular application, which has one li with ng-repeat and a text box for searching the out put in ng-repeat, the repeated item has a delete "X" button which deletes the record from DB. problem i am facing is how to remove searched record from the array using splice.
http://plnkr.co/edit/oPBofD2wL2ZUrD23f8Rr?p=preview
go to above plnkr click on any of the "x" without searching, then it will get removed from the list . but when you search for something lets say ruby then only ruby will come into the list but by clicking on "x" it will still appear . I need help in removing the searched field from the array using array operation, i dont want to regenerate that array again.
instead of just using the index as a parameter, calculate your index with a search of the json element in the array.
Like so:
$scope.delete = function(project) {
idx = $scope.projects.indexOf(project);
$scope.projects.splice(idx, 1);
};
DEMO
The problem is that your idx is set to $index. That is the index of the ng-repeat, not the index of the array so when the list is filtered you're now deleting the wrong element.
(You'll notice this if you clear the search-box after deleting)
If you change your HTML to
X
The delete function will receive the actual element that needs to be removed and can be rewritten to
$scope.delete = function(project) {
$scope.projects.splice($scope.projects.indexOf(project), 1)
};
The reason is that you are sending the $index for removing, instead of that pass the id like
X
Working Demo
Try this out
$scope.delete = function(idx) {
for ( var i = 0; i < $scope.projects.length; i++){
if ($scope.projects[i].id === idx)
{
$scope.projects.splice(i, 1);
}
}
};

update WinJS.Binding.List on Splice

I am building an App similar to the Grid App Template for Windows 8 using Javascript and the winJS framework. For one of my pages lots of my items have the same value and I have returned just 1 item for each of these different values using the .createFiltered. This is working great for adding new items because the .createFiltered method updates and checks to see if my new item has a new value.
The issue I am having is with removing items. When I splice the WinJS list there is a chance it is the removing the item which which the .createFiltered method has returned for the repeated value, but there are still other items about with that value. So i need the .createFiltered to run again and then pick a different item.
I will give you an example.
I have 5 items with 2 types's between them "Apple" and "banana".
On my home page I have sorted the items into Fruit / Vegetables / Sweets. These 5 items all come under fruit but instead of giving the different brands I just want it to say "Apple" and "Banana" so I have a function that will get one item for each type and bind it to a WinJS.Binding.Template and then use "textContent: Type" to display Apple / Banana.
Say I have 2 apples "Gala" and "Granny Smith" and I have bound the data of "Gala" to the home page and I then run out of "Gala" Apples (deleting it). I still have Apples in stock (Granny Smith) so I need to .createFiltered function to run again as the Home Page no longer displays "Apples" under Fruit.
Thank you
Since writing this I have managed to find a way to get it to work. What I have done is found the value of the item I am deleting and then gone through the array to see if I can find another item with that value. I have then removed that from the list and then re-added it causing .createFiltered to process the item.
The exact code:
function dashRefresh(toDelete) {
//Project Key of Deleted Item
var deletedProjectKey = toDelete.data.project.key;
//Use new item to bind project data
var newProjectBinder = 0;
var newProjectBinderIndex;
for (var i = 0; i < list.length; i++) {
var listItem = list.getAt(i);
if (listItem.project.key == deletedProjectKey) {
newProjectBinder = listItem;
newProjectBinderIndex = i;
i = list.length;
}
}
if (newProjectBinder != 0) {
list.splice(newProjectBinderIndex, 1);
list.push(newProjectBinder);
}
}

reading array json with javascript

I have this array tv, when I read this array with a loop for, it just give me the last item, in this case Toshiba,
how can I do to it show me the TV brands??
for (var i=0;i<tv.length;i++){
$('#item').html(tv[i].Brand)}
<div id='item'></div>
Array tv:
var tv = [{"Name":"TV","Brand":"Samsung"},
{"Name":"TV","Brand":"Toshiba"},
{"Name":"TV","Brand":"LG"}]
html() overwrites the content on each iteration, that's why only the last one is visible, the others are overwritten. You should be using append:
$('#item').empty();
for (var i=0; i<tv.length; i++){
$('#item').append(tv[i].Brand);
}
The problem: You have only one div#item element and you are updating its value in every iteration.
Solution: Dynamically create and append an element to show each item in the array like:
for (var i=0;i<tv.length;i++){
$('<div/>').addClass('item').html(tv[i].Brand).appendTo('.container');
}
where:
item is a class - now that you have multiple elements
container - assumed to the parent element under which you want the items displayed

Help with changing index in javascript/jquery

I have an javascript array, which looks like:
var styles = new Array();
styles[0] = { ... Position: 0, ... };
styles[1] = { ... Position: 1, ... };
styles[2] = { ... Position: 2, ... };
...
styles[N] = { ... Position: N, ... };
I use this array to display a list, where each item is a div. The end result is this:
<div id="container">
<div>... item 1...</div>
<div>... item 2...</div>
<div>... item 3...</div>
</div>
Now the "container" div is also jquery sortable. That way I can drag/drop the items and change the position. Now whenever the user drags an item to a different position I update the positions back in the array by looping through the div items, which is pretty bad. It looks more or less like that:
var items = $("#container");
for (var i = 0; i < items.length; i++)
{
....
styles[i] = { ... Position: i, ... };
}
Is there a better way to achieve this?
Update 1:
I need to save the positions in the database, which is why I need change my array after the list has been changed. The list changes depending on other criterias. So I could have a list of 10 items or I could have a list of X items. It depends on which list the users selects. Now if the user changes one list and then wants to see a second list, then I need to make sure that the first list maintains the positions.
I think Drew Wills response is on the mark, and this might also help. A div is a JavaScript object, which means you can add properties to it. So you might be able to reduce the number of lines of JavaScript code and increase the code's expressiveness by sticking your "information object" right onto each div, meaning you'd no longer need your array.
Where does your array come from in the first place? I'm going to assume it is a JSON-ified version of some data you have on the server. So I'm assuming (guessing) that you have some kind of "each" or for loop that creates the divs from the array, perhaps like this:
for (var i = 0; i < styles.length; i++)
{
var newDiv = $("<div>" + style[i].item + "</div>";
$("#container").append(newDiv);
}
Assuming you have that, then you could modify it to this:
for (var i = 0; i < styles.length; i++)
{
var newDiv = $("<div>" + style[i].item + "</div>";
// KEY NEW LINE FOLLOWS:
newDiv.myCustomObject = styles[i];
$("#container").append(newDiv);
}
Now, as the divs get sorted all over the place, this "myCustomObject" goes along with them. You don't need the array anymore. If you need the "Position" property on "myCustomObject" to be updated, use the "index" property of the div, as Drew Wills said.
So, imagine that your "styles" object has a property in it called "Color". Imagine you want to show an alert on click that tells the color associated with the div they clicked on. You can now accomplish this without needing the "styles" array, because the divs now have everything you need. So you could do this:
$("#container div").click(function() {
alert("The color is " + this.myCustomObject.Color);
});
Later, when it comes time to post or send via ajax the positions, you could do this:
$("#container div").each(function(index) {
this.myCustomObject.Position = index;
}
NOTE: Also, some people would prefer to use the JQuery data() method to associate "myCustomObject" with the div. It achieves the same result and perhaps gets garbage collected more completely in some browsers.
Why is it you need to know the position?
You won't have to track the position at all if you can rely on jQuery's $.index() method.
When you need to know the position of an element, just use something like the following...
$("#container div").index(myDiv);
UPDATE 1:
I see -- the server needs to know the positions to store them in the DB. Nevertheless, I'm not crazy about the notion of having 2 representations of this data on the page: markup (divs), and JS array. I would look at changing my code to build the array (from the divs) at the last second... just before you send it to the server. That way you can loop over the divs in order and you won't have to maintain the order in parallel in a separate data structure. Keeping 2 structures in sync in messy and can be error-prone
Little disclaimer: I don't know everything about your page. I don't know anything about your situation that would make this suggestion unworkable, but I suppose there may be something out there.
Little tip: if there are data elements int he area that aren't represented in the markup somehow, consider just tagging the markup with arbitrary info.
link text

Categories