I have a list of photographs being generated like the following snippet. Basically this would render a table like structure, with each photo being like a cell in this table. The ID of each photo like for example 1D means that the photo is in the first row of the table and in the 4th/D column.
<ul>
<li class="row">
<ul>
<li class="photo" id="photo-1A">1A</li>
<li class="photo" id="photo-1B">1B</li>
<li class="photo" id="photo-1C">1C</li>
<li class="photo" id="photo-1D">1D</li>
<li class="photo" id="photo-2A">2A</li>
<li class="photo" id="photo-2B">2B</li>
<li class="photo" id="photo-2C">2C</li>
<li class="photo" id="photo-2D">2D</li>
<li class="photo" id="photo-3A">3A</li>
<li class="photo" id="photo-3B">3B</li>
<li class="photo" id="photo-3C">3C</li>
<li class="photo" id="photo-3D">3D</li>
</ul>
</li>
</ul>
I have a JSON which includes whether the photo is available or not. Basically the JSON string is something along these lines:
[{"row":1,"position":"A","available":true},{"row":1,"position":"B","available":false},{"row":1,"position":"C","available":false},{"row":1,"position":"D","available":false},{"row":2,"position":"A","available":true},{"row":2,"position":"B","available":false},{"row":2,"position":"C","available":false},{"row":2,"position":"D","available":false},{"row":3,"position":"A","available":true},{"row":3,"position":"B","available":false},{"row":3,"position":"C","available":false},{"row":3,"position":"D","available":false}]
Now basically what I need to do is to parse this JSON string and when any of these photos have "available:true" in the JSON string, I add a class photo-available in the HTML. I am new to angular and I am not sure if there is an easy way to assign a class to the available photos. Would be glad if someone can tell me what to use or how to do it.
Edit: Angular Code is this:
<ul class="table-rows">
<li class="photo-row" ng:repeat="photo in photos" ng:class="'photo-' + photo.row + photo.position">
<ul class="table-photos">
<li class="photo photo-available" ng:class="selectedOrNot(photo)" ng:init="photo.selected = false" ng:click="photo.selected = !photo.selected">
<div class="photo-number">{{photo.row + photo.position}}</div>
</li>
</ul>
</li>
<div class="clear"></div>
Update3
The reason you are unable to restore previous selections is that you are overwriting the photo's selected property with ng-init:
ng:init="photo.selected = false"
ng-class="{'selected': photo.selected, 'available': photo.available}"
When you combine these two, the 'selected' class will never be added because photo.selected has been hardcoded to false. You just need to remove ng-init, and the previous selection will trigger ng-class to add the correct class.
Here is a working demo: http://plnkr.co/tVdhRilaFfcn55h6mogu
Original answer
If the list of photos is not the same array as the list of available photos, you can use a directive to add the class.
app.directive('availablePhoto', function($filter) {
return {
restrict: 'A',
scope: true,
link: function(scope, element, attr) {
var id = attr.id
var regex = /photo-(.)(.)/g;
var match = regex.exec(id);
var row = match[1]
var position = match[2]
var photo = $filter('filter')(scope.photos, {row:row, position:position}, false)
console.log(photo);
if (photo[0].available) {
element.addClass('available');
}
}
}
});
Then attach it to each list item like this:
<li class="photo" id="photo-1A" available-photo>1A</li>
Here is a demo: http://plnkr.co/WJCmLf2M39fcUnvOPyNA
Update1
Based on your update, I see that there is just one array populating the list, and it contains the available flag. Therefore, you don't need a custom directive - ngClass will work. Here it is integrated into your code sample:
<ul class="table-rows">
<li class="photo-row" ng:repeat="photo in photos" ng:class="'photo-' + photo.row + photo.position">
<ul class="table-photos">
<li class="photo" ng-class="{'available': photo.available}" ng:init="photo.selected = false" ng:click="photo.selected = !photo.selected">
<div class="photo-number">{{photo.row + photo.position}}
</div>
</li>
</ul>
</li>
<div class="clear"></div>
</ul>
I have update the plunker to demonstrate this.
http://plnkr.co/WJCmLf2M39fcUnvOPyNA
Update2
Since you need ngClass to add multiple classes, use it like this:
ng-class="{'selected': photo.selected, 'available': photo.available}"
Demonstration of selected + available: http://plnkr.co/WJCmLf2M39fcUnvOPyNA
Here's a plnkr with an example of how to solve your problem. You need to
make use of both the ng-repeat and the ng-class:
http://plnkr.co/edit/hk68qp4yhEjcvOkzmIuL?p=preview
As you can see, I also added some filters for your photos, they will come handy if you need to just show the available ones (for some reason).
Here's the documentation for angular $filter service
I think this meets all your requirements:
$scope.photos = JSON.parse('[{"row":1,"position":"A","available":true},{"row":1,"position":"B","available":false},{"row":1,"position":"C","available":false},{"row":1,"position":"D","available":false},{"row":2,"position":"A","available":true},{"row":2,"position":"B","available":false},{"row":2,"position":"C","available":false},{"row":2,"position":"D","available":false},{"row":3,"position":"A","available":true},{"row":3,"position":"B","available":false},{"row":3,"position":"C","available":false},{"row":3,"position":"D","available":false}]');
and then you can just use ng-repeat to build the list:
<ul>
<li class="row">
<ul>
<li ng-repeat="photo in photos" class="photo" ng-class="{'photo-available': photo.available}" id="photo-{{photo.row}}{{photo.position}}">{{photo.row}}{{photo.position}}</li>
</ul>
</li>
</ul>
So what we are doing is we are taking our photo array, and for every one (ng-repeat="photo in photos") we are assigning that specific item to the variable photo. Then, if photo.available is true, we assign the class photo-available (ng-class="{'photo-available': photo.available}").
Then, we can simply interpolate the id and text based off the properties row and position ({{photo.row}}{{photo.position}}). You could also have done that like this {{photo.row + photo.position}} but that could cause issues if they were both numbers.
http://plnkr.co/edit/hBkoyHVtIwF60MKDF84j?p=preview
Related
I have a nested list:
<ul>
<li id="1">first</li>
<li id="2">second</li>
<ul>
<li id="2-1">second nested first element</li>
<li id="2-2">second nested secondelement</li>
<li id="2-3">second nested thirdelement</li>
<ul>
<li id="2-3-1">Other</li>
</ul>
</ul>
<li id="3"i>third</li>
<li id="4">fourth</li>
</ul>
Each element has an id that indicates the position within the list. How do I generate it automatically?
Thank you.
UPDATE:
html is generated by Apache velocity without ID. I'm trying to create a method for updating the id if you move elements with jquery sortable. The structure of the id must be "1" for the first item "1-1" for the first element of the first "li". I tried using index () but I can't generate the id in the form that I need
It's not clear what you exactly want to do here, but here's an example of generating dynamic li's with dynamic id's:
HTML:
<ul id="autoGenerated">
</ul>
JS:
for(var i = 1; i < 3 ;i++){
$("#autoGenerated").append("<li id=2-" + i + ">Testing " + i + "</li>")
}
$('#autoGenerated li').click(function(){
alert($(this).attr("id"));
})
Fiddle.
I have a nested set of objects I would like to sort. The first example, directly below, is my prototype / test. It works nicely. The outer groups sort, and the inner groups sort. the inner groups are locked inside - cant be moved outside. Just exactly like i want...
<div id="example5">
<ul class="table">
<li class="group" style="width:300px;">Group 1
<ul style="padding:0px;">
<li class="field">Group 2</li>
<li class="field">Group 3</li>
</ul>
</li>
<li class="group">Group 2</li>
<li class="group">Group 3</li>
<li class="group">Group 4</li>
</ul>
</div>
And
$("#example5 ul").sortable({
});
This is the same structure I am trying to impart in my program. Everything seems the same to me, just with some added complexity. Clearly, I am breaking it somehow. The outer groups sort, while the inner ones do not.
I think its important to note that in the previous example, the script and html are in the same file. In the second example, below, the html is dynamically created with createElement() function
<div id="logtable">
<ul id="ultable" class="table ui-sortable">
<li id="" class="groupcontainer" style="width:auto; margin:2px;">
<ul>
<li class="fieldcontainer">
<div class="fieldname"></div>
<div class="fieldgroup"></div>
<div class="fieldname"></div>
<div class="fieldname"></div>
<div class="fieldname"></div>
</li>
</ul>
</li>
<li id="a" class="groupcontainer" style="margin: 2px;"></li>
<li class="groupcontainer" style="margin: 2px;"></li>
</ul>
</div>
Javascript:
$(function() {
var fieldstart;
var fieldend;
$("#logtable ul").sortable({
start: function(event, ui) {
fieldstart = ui.item.index();
},
update: function(event, ui) {
fieldend = ui.item.index();
var fieldcount = jsonstring.tracelog.fields.length;
var fieldobjects = jsonstring.tracelog.fields;
var placed = false;
jsonstring.tracelog.fields.move(fieldstart, fieldend);
writejson();
}
});
});
Following up, this site... http://www.trace-log.com/sortworks.php is copied from the "inspect element" output. it works exactly like i want. http://www.trace-log.com is the site i generated it from. basically, add a value to the field name, it will generate a new field. entering a value in the first text box will initiate the "grouping" of fields. cant understand why this isn't working.
so as it stands, it works if i statically recreate the page, but doesnt work correctly on the dynamically created page. could it be somehow with the way the sortable function is being called?
In the second example the field container is an li and the field names are div tags. The first example you had the field container as an ul tag and the fields as li. I think this might be your issue.
see fiddle here http://jsfiddle.net/4Mk4K/3/
You can try adding a custom class to the elements you want to be sortable and then use that class in the items option of sortable.
Demo:http://jsfiddle.net/lotusgodkk/GCu2D/161/
HTML:
<div id="logtable">
<ul id="ultable" class="table ui-sortable">
<li id="" class="groupcontainer item" style="width:auto; margin:2px;">Z
<ul>
<li class="fieldcontainer">
<div class="fieldname item">A</div>
<div class="fieldgroup item">B</div>
<div class="fieldname item">C</div>
<div class="fieldname item">D</div>
<div class="fieldname item">E</div>
</li>
</ul>
</li>
<li id="a" class="groupcontainer item" style="margin: 2px;">F</li>
<li class="groupcontainer item" style="margin: 2px;">G</li>
</ul>
</div>
JS:
$(function () {
var fieldstart;
var fieldend;
$("#logtable ul").sortable({
items: '.item',//Custom class of items which needs to be sorted.
start: function (event, ui) {
fieldstart = ui.item.index();
},
});
});
After much fiddling and fussing, relocating the sortable function into the function that creates the DOM objects solved the problem. I think the way it was originally structured, some DOM objects were created AFTER the sortable function - and sortable didn't know they existed.
So yes, there was something else structurally wrong with my code. Thanks everyone for the help.
Im trying to rearrange a list. I've got for example a list with categories:
<ul class="category">
<li class="cat1 active">cat1</li>
<li class="cat2 active">cat2</li>
<li class="cat3">cat3</li>
<li class="cat4">cat4</li>
</ul>
and a list with subjects
<ul class="subjects">
<li class="sub1">sub1</li>
<li class="sub2">sub2</li>
<li class="sub3">sub3</li>
<li class="sub4">sub4</li>
<li class="sub5">sub5</li>
<li class="sub6">sub7</li>
<li class="sub7">sub7</li>
<li class="sub8">sub8</li>
</ul>
What I want to do is when a certain category has the class active, some subjects will go to the top of the list. for example like this:
<ul class="subjects">
<li class="sub3">sub3</li>
<li class="sub5">sub5</li>
<li class="sub8">sub8</li>
<li class="sub1">sub1</li>
<li class="sub2">sub2</li>
<li class="sub4">sub4</li>
<li class="sub6">sub6</li>
<li class="sub7">sub7</li>
</ul>
I can do this with this code:
if($('li.cat1').hasClass('active')){
$('.sub3, .sub5, .sub8').insertBefore($('.subjects li:first-child'));
}
But then the real problem starts when multiple categories is active. I have done it like so:
if($('li.cat1').hasClass('active')){
$('.sub3, .sub5, .sub8').insertBefore($('.subjects li:first-child'));
}
if($('li.cat2').hasClass('active')){
$('.sub3, .sub4, .sub7').insertBefore($('.subjects li:first-child'));
}
The result is this:
<ul class="subjects">
<li class="sub4">sub4</li>
<li class="sub7">sub7</li>
<li class="sub3">sub3</li>
<li class="sub5">sub5</li>
<li class="sub8">sub8</li>
<li class="sub1">sub1</li>
<li class="sub2">sub2</li>
<li class="sub6">sub6</li>
</ul>
the order is now 4,7,3,5,8. Those are the numbers that have been selected but how do I rearrange them into: 3,4,5,7,8,1,2,6? Could someone help me with this? Here is the JsFiddle http://jsfiddle.net/NTPd4/2/
You could do 2 things to make it ALL good. First, make an sort method to suit your needs (i went by alpha of inner html, pik your poison). Second, make a variable for a jQuery object you can simply add elements too.
Next, use the variable in your if statements to gather the elements you want. Then before inserting, sort them!
Example
function sortAlpha(a,b){
return a.innerHTML.toLowerCase() > b.innerHTML.toLowerCase() ? 1 : -1;
};
var activeSubjects = $();
if ($('li.cat1').hasClass('active')) {
activeSubjects = activeSubjects.add($('.sub5, .sub3, .sub8'))
}
if ($('li.cat2').hasClass('active')) {
activeSubjects = activeSubjects.add($('.sub3, .sub4, .sub7'))
}
activeSubjects.sort(sortAlpha).insertBefore($('.subjects li:first-child'));
I think the .add will sort them automigikally, but keep in mind, you could also use the sort function straightforward, like:
$('.sub5, .sub3, .sub8').sort(sortAlpha);
Also, for your current setup (where all text is same except for number) you could use a sort function like:
function sortNum(a,b) {
return parseInt($(a).text().substring(3)) - parseInt($(b).text().substring(3));
}
However, the sortAlpha will probably better suite your needs in the long run. As I mentioned before, you can arrange your sort function how you like.
If you want all five elements in their original order, you need to move them at the same time. Use .add() to combine them:
$('.sub3, .sub5, .sub8').add('.sub3, .sub4, .sub7').prependTo($('.subjects'));
Or, integrating it into your code:
var $selector = $();
if ($('li.cat1').hasClass('active')) {
$selector = $selector.add('.sub3, .sub5, .sub8');
}
if ($('li.cat2').hasClass('active')) {
$selector = $selector.add('.sub3, .sub4, .sub7');
}
$selector.prependTo('.subjects');
http://jsfiddle.net/mblase75/GYfpv/
I have a widget that has the following structure (it's a "plan selector" resume):
<div>
<ul>
<li resume="to" ng-repeat="item in items"></li>
</ul>
<div class="total"></div>
<ul>
<li resume="from" ng-repeat="item in items"></li>
</ul>
</div>
my directive is the following:
plans.directive('resume', function() {
return {
restrict: 'A',
template: '<h3>{{step.name}}</h3><div>{{val}}</div>',
link: function($scope, element, attrs, controller) {}
};
});
Notes:
plans is an angular.module('Plans')
items is some data that is loaded via AJAX, and each item has a selected attribute
they share the same controller as the items that will be selected, that is PlansCtrl
What I want:
When the user finishes selecting the items (setting each "selected"), it will only show in the "to" when it's selected, and it will only show in the "from" when it's not selected. I don't want to hard code anything because everything is mounted using AJAX.
Assuming I'm understanding you right, it's probably better to use the filter filter like so:
http://jsfiddle.net/qbGeG/
<div ng-app ng-controller="x">
<b>selected</b>
<ul>
<li ng-repeat="item in items | filter:{selected:true}" ng-click="item.selected = !item.selected">{{item.name}}</li>
</ul>
<div class="total"></div>
<b>unselected</b>
<ul>
<li ng-repeat="item in items | filter:{selected:!true}" ng-click="item.selected = !item.selected">{{item.name}}</li>
</ul>
</div>
If you need the functionality as a directive, then it would be better to replace the entire li element with something like: <selectableList source="items" /> where your directive just uses filter and ngClick like I did above.
Im working on html form and I have used dynatree for select and multi-select as per requirement of the project. What I need to do is to make a edit form where user gets all the fields filled from database. Which means i need to show a user a dynatree with already selected fields. Here is my example code :
<span id="action" name="action">
<ul>
<li id="DisruptiveAction" class="folder expanded">DisruptiveAction (5)
<ul>
<li id="allow" title="optional">allow
<li id="deny" title="optional">deny
<li id="pass" title="optional" class="selected" >pass
<li id="block" title="optional">block
<li id="redirect" title="optional">redirect
</ul>
</ul>
</span>
Java script :
$("#action").dynatree({
classNames: {
container: "action-container",
checkbox: "dynatree-radio"
},
selectMode: 3,
onSelect: function(select, node) {
var selKeys = $.map(node.tree.getSelectedNodes(), function(node){
return node.data.key;
});
$("#selectedAction").val(selKeys.join(","));
var selRootNodes = node.tree.getSelectedNodes(true);
var selRootKeys = $.map(selRootNodes, function(node){
return node.data.key;
});
}
});
In above mentioned html even though Im using class = "selected" with an li element but its still not showing it as selected on UI. Thanks in advance.
Dynatree creates its own elements when initializing, and throughout the lifetime of the tree. Therefore, the li elements that you are adding are not the li elements of the tree.
Take a look at this documentation, under the section "Node Options". You'll see that you can add a class like so:
<div id="tree">
<ul>
<li id="DisruptiveAction" class="folder expanded">DisruptiveAction (5)
<ul>
<li id="allow" title="optional">allow
<li id="deny" title="optional">deny
<li id="pass" title="optional" data="addClass: 'dynatree-selected'" >pass
<li id="block" title="optional">block
<li id="redirect" title="optional">redirect
</ul>
That is generic code for adding a class. There might a more specific way of specifying that an element is selected, as it is a core dynatree concept, rather than a user-defined class.