Angular UI Sortable get index after updated - angularjs

I really dislike how angular-ui is documented. Sometimes they really don't explain a lot. This is the documentation to sortable-ui: https://github.com/angular-ui/ui-sortable
First, I cannot pass in options.
$scope.sortableOptions = {
cursor:"move"
};
I also changed "move" to "pointer" or "crosshair". Nothing happens.
Second, I need to update the backend by the new order of which the user has sorted. I am not a great javascripter at all (more of a back end developer). The only order-related js function I can find is indexof(). Then it gets very complicated because I need to iterate through all elements and find the new order since the user has rearranged all the elements.
Is there an easier way to get the current order of the list whenever the sortable directive is updated?
I created a demo on plunker (since it allows me to add extra libraries)
http://plnkr.co/edit/uNErHgKL3ohNyFhgFpag?p=preview
Again the cursor part is not working, and I have no idea how to get the order of these items.
I see there are methods on the Sortable UI page...I'm new to angularJS. I just couldn't figure out how to call these methods within AngularJS code.
Seralize method/toArray might not be a good idea..The actual data I'm dealing with does not look like ["one", "two", "three"]. It's more like:
[{"id":"5","article_name":"New Article
Title","article_order":"1","article_author":"Author","article_body":"Start typing your
article here!","is_visible":"1","created_date":"2013-10-27
05:37:38","edit_date":null,"magazineID":"7"},
{"id":"13","article_name":"New Article
Title","article_order":"2","article_author":"Author","article_body":"Start typing your
article here!","is_visible":"1","created_date":"2013-10-27
05:45:10","edit_date":null,"magazineID":"7"}]
If you guys look into this data stream..there is one attribute called article_order. This is the attribute (database column) I am trying to modify...

Read the jQuery UI Sortable docs. There are lots of events you can bind to and methods for serializing the sorted elements. Within the event callbacks you want to use you can make ajax calls to server with updated data
This angular module is simply a wrapper for jQuery UI Sortable.
Create a demo in jsfiddle or plunker that shows the problems you are having

If you use my new sortable Angular.js directive, you would do it like this:
$scope.items = [{"id":"5","article_name":"New Article
Title","article_order":"1","article_author":"Author","article_body":"Start typing
your article here!","is_visible":"1","created_date":"2013-10-27
05:37:38","edit_date":null,"magazineID":"7"},
{"id":"13","article_name":"New Article
Title","article_order":"2","article_author":"Author","article_body":"Start typing
your article here!","is_visible":"1","created_date":"2013-10-27
05:45:10","edit_date":null,"magazineID":"7"}];
$scope.onChange(fromIdx, toIdx) {
$scope.items[fromIdx].article_order = toIdx;
$scope.items[toIdx].article_order = fromIdx;
// OR
// var temp = $scope.items[fromIdx].article_order;
// $scope.items[fromIdx].article_order = $scope.items[toIdx].article_order;
// $scope.items[toIdx].article_order = temp;
}
HTML:
<ul ng-sortable="items"
ng-sortable-on-change="onChange">
<li ng-repeat="item in items" class="sortable-element" ng-style="{backgroundColor: item.color}">
{{item.name}}, {{item.profession}}
</li>
</ul>
See demo + documentation here:
https://github.com/schartier/angular-sortable
https://github.com/schartier/angular-sortable-demo

I guess I got into an issue similar to you. If we subscribe the update callback we don't get the latest order of items. But using the stop event handler helped me. While using angular ui sortable, we get the model updated with the latest order in the stop event handler. You can post this data to backend or wherever you want to store..Hope this helps...:)
You can refer the jquery ui sortable documentation for stop here
http://api.jqueryui.com/sortable/#event-stop

Related

ChartistJS : Converting jQuery solution to AngularJS

I am using Chartist JS for my charts in my Angular JS app. The issue is I am seeing this here. There is a JS bin that highlights the issue. The author gives a solution for it. The solution is doing DOM manipulations in Jquery which is easy to do. However with AngularJS the way you manipulate the DOM is via Directives. I have created a plunker here which highlights the same issue in Angular JS but I am confused as to how to put the solution provided by author into my Angular code.
Here is the solution
$('[data-tab]').on('toggled', function (event, tab) {
tab.find('.ct-chart').each(function(i, e) {
e.__chartist__.update();
});
});
Edit: As requested the JSFiddle is updated, so what I am trying to do is. I have three different tabs and three different graphs, whenever I click on them I should see the respective graph. To make the tab behavior possible I have written a basic code using scope and model. which facilitates the changing of tabs. The issue is that the chart is getting created for first or default tab but not for the second and third tab. There is a solution given by the author but I don't know how to implement that in AngualrJS
the jQuery solution that you post is basically finding all the chart references and then doing DOM manipulation and call the update() function.
The key is how to find the chart to update in Angular.
In this case, you can assign a variable when you create a chart. For example:
var chart4 = new Chartist.Bar('#chart4', data1);
var chart5 = new Chartist.Bar('#chart5', data2);
Now you have the reference of the chart. All you have to do is to call update() function to render the chart again.
if (value === "allDrivers") {
$scope.tab = "All";
chart4.update();
}
Here is the working plunker
One thing I like to point out is: right now you need to double click the tab in order to see the chart is being rendered or you resize the browser window. I am still trying to find a way to fix this. But at least this approach gives you an idea how to convert the jQuery solution to Angular solution.
I was able to solve this using angular.element() method. So if you wish you use jquery in your angular code. You have to do this via angular.element method. But make sure to include jquery before angular in your index.html
If jQuery is available, angular.element is an alias for the jQuery
function. If jQuery is not available, angular.element delegates to
Angular's built-in subset of jQuery, called "jQuery lite" or jqLite.
I did not know this. From here it was learning for me. Following advice of #pieterjandesmedt from this post. I was able to do this. For other people who want to learn how this works. I have created a GitHub repo which gives a solution to this issue. The link for problem is given in the question. Hope that helps

Backbone JS - event problems adding multiple Views into same parent container

My code fetches a Collection from the server and iterates through it. For each model fetched it creates a View that is appended to the same parent element. Each of these views has a "click" event that triggers a function.
The problem is that clicking on any item in the list causes the event function to trigger for ALL elements in the list. The only workaround I have is to make the function itself dynamic and try to determine if it should run based on things like the ID of the item clicked:
'click .request_box': function(e) {
var myid = $(e.currentTarget).attr("id");
// code here which determines whether the function runs
}
}
This is a workaround, but it is also a hack, and I'm sure there has to be a better way of dealing with what must be a common problem (creating a list). Repeat searching around the web does not suggest any better way, so I am posting in the hope someone with more experience using Backbone can offer suggestions on a better way to approach this problem....
Thank you in advance.

Sorting in Angular

I am building an app using Angular.
I have JSON that comes back from the server sorted by date.
I bind to this data in the view.
A user may change what data is displayed in the view. This kicks off a request and the view gets updated as it is bound to the JSON data changes.
When Angular gets this JSON data it then sorts it alphabetically.
I want to maintain the sort order that comes from the server.
I googled this a bit and found the following solution...
<div ng-repeat="key in notSorted(myData)" ng-init="data = myData[key]">
"notSorted" is a function on the controller...
$scope.notSorted = function(obj){
if (!obj) {
return [];
}
return Object.keys(obj);
}
This works fine initially. The data displays in the correct order.
However it breaks the binding. So when the user tries to change the data being displayed, the view does not get updated as notSorted does not see the binding change.
I can think of a few hacky ways around this such as manually firing the updates but I would like to do this the correct angular way.
Anyone know what that is?
Thanks
I believe you need this:
https://docs.angularjs.org/api/ng/filter/orderBy
It works sort of like this:
<div ng-repeat="item in items | orderBy:'key'">
Because of the way the data was coming back from the server and how I needed to iterate over that data I wasn't able to get any of the "orderBy" or filter solutions to work.
However I discovered that in Angular 1.4 they removed the default ordering (alphabetical/ascending) in favour of preserving the order the data was returned from the server...
http://jaxenter.com/angular-releases-1-3-update-1-4-beta-113906.html
I was using 1.3.x and simply updated to 1.4 and it worked OOTB.
Thanks

ng-repeat moves dom elements around, which breaks a ckeditor because it doesn't support having it's dom elements moved

I'm trying have an ng-repeat which contains divs that include a CKEDITOR instance. The list is sortable by a few different properties. However, when the list is resorted, the CKEDITORs break because they don't support being moved around in the DOM. The only solution I can think of is to destroy the CKEDITOR instance before sort, and recreate them after. Is there any events on ng-repeat that can accomplish this?
plunkr here: http://plnkr.co/edit/tGnTdzvRl7xhEX7zYq4c?p=preview
Was able to get this fixed eventually. Pretty easy now that I think about, but took me 3 days to realize it. Instead of trying to listen for events on ng-repeat, catch the event that is causing the data to be modified. For me, it was jquery UI sortable (angular directive.) In the controller add $scope.$broadcast('unbind-ckeditor') before the change, and then $scope.$broadcast('rebind-ckeditor') after it. In your angularjs directive for ckeditor, call scope.$on('unbind-ckeditor', function() {instance.destroy /* instance is your ckeditor instance*/}); and then reload it in the rebind. Hope this helps someone.
Edit:
Make sure the $on('unbind-ckeditor'... is only added to the scope once, or multiple sorts will throw exceptions.
The solution for me:
use divArea and not iframe, this will work with ng-repeat when the list changed.
using other textarea (hidden) and monitoring it as the ng-sortable+ckeditor broke the order of CKEditors.
in ng-sortable (who make the change in the list) I was added this code:
$rootScope.$broadcast('rebind-ckeditor'); console.log("rebind")
and in CKEDITOR directive:
scope.$on('rebind-ckeditor', function () {
if (jQuery(element).data("loaded")) {
console.log("rebind");
CKEDITOR.instances[element[0].id].destroy();
jQuery(element).data("loaded", null);
element[0].value = $("textarea", element.parent())[1].value; // update manualy from the hidden textarea
onLoad(); //recreate CKE after textarea changed.
}
})

Having a set of checkboxes map to a nested array

I am working on a SPA that pulls in customer data from one $resource call, and gets some generic preference data from another $resource call.
The preference data is sent as an array, which I want to use to populate a series of checkboxes, like so:
<div ng-repeat="pref in fieldMappings.mealPrefs">
<input type="checkbox"
id="pref_{{$index}}"
ng-model="customer.mealPrefs"
ng-true-value="{{pref.name}}" />
<label class="checkbox-label">{{pref.name}}</label>
</div>
When a user clicks one or more checkboxes, I want the values represented in that array of checkboxes to be mapped to an array nested inside a customer object, like so:
.controller( 'AppCtrl', function ( $scope, titleService, AccountDataService ) {
// this is actually loaded via $resource call in real app
$scope.customer = {
"name": "Bob",
"mealPrefs":["1", "3"]
};
// this is actually loaded via $resource call in real app
$scope.fieldMappings.mealPrefs = [
{'id':"1", 'name':"Meat"},
{'id':"2", 'name':"Veggies"},
{'id':"3", 'name':"Fruit"},
{'id':"4", 'name':"None"}
];
});
I have tried setting up ng-click events to kick off functions in the controller to manually handle the logic of filling the correct part of the customer object model, and $watches to do the same. While I have had some success there, I have around 2 dozen different checkbox groups that need to be handled somehow (the actual SPA is huge), and I would love to implement this functionality in a way that is very clean and repeatable, without duplicating lots of click handlers and setting up lots of $watches on temporary arrays of values. Anyone in the community already solved this in a way that they feel is pretty 'best practice'?
I apologize if this is a repeat - I've looked at about a dozen or more SO answers around angular checkboxes, and have not found one that is pulling values from one object model, and stuffing them in another. Any help would be appreciated.
On a side-note, I'm very new to plunkr (http://plnkr.co/edit/xDjkY3i0pI010Em0Fi1L?p=preview) - I tried setting up an example to make it easier for folks answer my question, but can't get that working. If anyone wants to weigh in on that, I'll set up a second question and I'll accept that answer as well! :)
Here is a JSFiddle I put together that shows what you want to do. http://jsfiddle.net/zargyle/t7kr8/
It uses a directive, and a copy of the object to display if changes were made.
I would use a directive for the checkbox. You can set the customer.mealPrefs from the directive. In the checkbox directive's link function, bind to the "change" event and call a function that iterates over the customer's mealPrefs array and either adds or removes the id of the checkbox that is being changed.
I took your code and wrote this example: http://plnkr.co/edit/nV4fQq?p=preview

Resources