I have a jquery accordion with selectable lists inside. When the user clicks an item, it appears in their selected items list, which is sortable. There are a number of columns that appear in their list as default columns, and each item selected shows up as green in the accordion.
My issue is that line items with two words in the sortable list are not sortable, but items with one word are. I cannot figure out why. Any thoughts?
Here's my fiddle: http://jsfiddle.net/kmbonin82/NkgC2/9/
HTML:
<h3>List 1</h3>
<ul class="list">
<li id="Country">Country</li>
<li id="Region">Region</li>
<li id="Location_Name">Location Name</li>
<li id="Location_Start">Location Start</li>
</ul>
<h3>List 2</h3>
<ul class="list">
<li id="Contract_Start">Contract Start</li>
<li id="Contract_Status">Contract Status</li>
<li id="Contract">Contract</li>
</ul>
<p id="feedback">
<span>You've selected items:</span>
<ul id="select-result">
<li id="Region">Region</li>
<li id="Location Name">Location Name</li>
<li id="Country">Country</li>
<li id="Contract Status">Contract Status</li>
</ul>
</p>
JS:
$(function () {
$(".list").selectable({
stop: function () {
var result = $("#select-result");
$(".ui-selected", this).each(function () {
$(this).css('background-color', '#669966');
$(this).css('color', '#FFFFFF');
result.append('<li id="' + $(this).text() + '">' + $(this).text() + '</li>');
sortColumns();
});
}
});
sortColumns();
});
$(function () {
$("#accordion").accordion({
collapsible: true,
autoHeight: false
});
});
$(function () {
$("#select-result li").each(function (index) {
var thisID = $(this).attr('id');
thisID = thisID.replace(/ /g, '_');
document.getElementById(thisID).style.background = '#669966';
document.getElementById(thisID).style.color = '#FFFFFF';
sortColumns();
});
});
function sortColumns() {
$(function () {
$("#select-result")
.sortable({
handle: ".handle",
over: function () {
removeIntent = false;
},
out: function () {
removeIntent = true;
},
beforeStop: function (event, ui) {
if (removeIntent == true) {
var thisID = ui.item.text();
thisID = thisID.replace(/ /g, '_');
ui.item.remove();
document.getElementById(thisID).style.background = '#FFFFFF';
document.getElementById(thisID).style.color = '#000000';
}
}
})
.find("li")
.addClass("ui-corner-all")
.prepend("<div class='handle'><span class='ui-icon ui-icon-carat-2-n-s'></span></div>");
});
}
The 'Location Name' and the 'Contract Status' are not sortable because their id values are wrong. You have space between them.
<li id="Location Name">Location Name</li>
<li id="Contract Status">Contract Status</li>
Updated Demo: http://jsfiddle.net/NkgC2/10/
Bonus:
a) the way you are pre-pending the div is not a right way. If you see your html code, after each item you select it adds an extra div for each list item
b) Instead of calling sortable() function couple times (it get calls 3 times before even selecting any item. ) use jquery 'on' method to bind api to non-existing elements.
Related
I'm trying to filter a list based on a selection from a bootstrap dropdown, but cannot seem to get it to work. Here's my code:
<body>
<div class="toolbar-wrapper" >
<div class="btn-group container" role="group" ng-controller="filterController">
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
{{filter}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li ng-repeat="severity in severityLevels">{{severity}}</li>
</ul>
</div>
</div>
</div>
<div class="logMessages" ng-controller="logController">
<div >
<ul>
<li class="message" ng-repeat="logData in data | filter: filter | limitTo: quantity">
{{logData.timestamp}} : {{logData.severity}} : {{logData.message}}
</li>
</ul>
</div>
</div>
</body>
Javascript:
var app = angular.module('UnifyLog', []);
app.controller('filterController', function($scope) {
$scope.severityLevels = [
'ERROR',
'WARN',
'INFO',
'DEBUG'
];
$scope.filter = '';
$scope.resetFilter = function() {
$scope.filter = '';
};
$scope.changeSeverity = function(severity) {
$scope.filter = severity;
}
})
.controller('logController', function ($scope, $http) {
$http.get("https://clock/settings/get_log_messages", {}).then(
function (response) {
$scope.data = response.data;
},
function (response) {
console.log("fail:" + response);
}
);
$scope.quantity=100
});
I know you can use ng-model data binding with a select directive, but I want to use a bootstrap dropdown.
The code above is updating the scope.filter variable but the list of log messages does not filter.
The http request is getting back a json array with log data objects containing message, timestamp, and severity fields.
Try calling $scope.apply():
$scope.changeSeverity = function(severity) {
$scope.filter = severity;
$scope.apply()
}
Look here for more information, and consider another approach (use real data-binding instead of a custom callback): https://github.com/angular/angular.js/wiki/When-to-use-$scope.$apply()
I would create a customer severity filter like so:
.filter('severityFilter', function () {
return function (input, severity) {
var out = [];
if (input && input != []) {
angular.forEach(input, function (thing) {
if(thing.severity === severity){
out.push(thing);
}
});
}
return out;
}
})
Then apply it like this:
ng-repeat="logData in data | severityFilter: severity | limitTo: quantity">
HTML code
In the second controller when I am trying to show the values in "itemBought List" on click of button its rendering empty string for name and quantity while I have data for the same in itemToBuy.itemList".
It seems the datas for name and quantity are not passed into the addItemToBoughtList() function. How to achieve that.
<!-- To Buy List -->
<div class="col-md-6" ng-controller="ToBuyController as itemToBuy">
<h2>To Buy:</h2>
<ul>
<li ng-repeat="item in itemToBuy.itemList"> Buy {{item.itemQuantity}} of {{item.itemName}}
<button class="btn btn-default" ng-click="itemToBuy.addItemToBoughtList()"><span class="glyphicon glyphicon-ok"></span> Bought</button></li>
</ul>
<div class="emptyMessage">Everything is bought!</div>
</div>
<!-- Already Bought List -->
<div class="col-md-6" ng-controller="AlreadyBoughtController as itemBought">
<h2>Already Bought:</h2>
<ul>
<li ng-repeat="item in itemBought.items">
Bought {{ items.quantity }} of {{ item.name }}</li>
</ul>
<div class="emptyMessage">Nothing bought yet.</div>
</div>
</div>
Javascript code
(function (){
'use strict';
angular.module('ShoppingListCheckOff', [])
.controller('ToBuyController', ToBuyController)
.controller('AlreadyBoughtController', AlreadyBoughtController)
.service('ShoppingListCheckOffService',ShoppingListCheckOffService);
ToBuyController.$inject = ['ShoppingListCheckOffService'];
function ToBuyController(ShoppingListCheckOffService) {
var itemToBuy= this;
itemToBuy.itemName = "";
itemToBuy.itemQuantity = "";
itemToBuy.itemList = [
{itemName : 'cookies', itemQuantity : 10},
{itemName : 'napkins', itemQuantity : 15}
];
itemToBuy.addItemToBoughtList = function () {
ShoppingListCheckOffService.addItemToBoughtList(itemToBuy.itemName, itemToBuy.itemQuantity);
}
}
AlreadyBoughtController.$inject = ['ShoppingListCheckOffService'];
function AlreadyBoughtController(ShoppingListCheckOffService) {
var itemBought = this;
itemBought.name="";
itemBought.items = ShoppingListCheckOffService.getItems();
}
function ShoppingListCheckOffService() {
var service = this;
// List of shopping items
var items = [];
service.addItemToBoughtList = function (itemName, quantity) {
var item = {
name: itemName,
quantity: quantity
};
items.push(item);
};
service.getItems = function ()
return items;
};
}
})();
Pass Item to your addItemToBoughtList function
<ul>
<li ng-repeat="item in itemToBuy.itemList"> Buy {{item.itemQuantity}} of {{item.itemName}}
<button class="btn btn-default" ng-click="itemToBuy.addItemToBoughtList(item)"><span class="glyphicon glyphicon-ok"></span> Bought</button></li>
</ul>
and receive it in your function in js
itemToBuy.addItemToBoughtList = function (item) {
ShoppingListCheckOffService.addItemToBoughtList(item.itemName, item.itemQuantity);
}
I have created a plunker with your code. It is working fine, have a look
Left hand side of the page is displaying list of task force.
On click of the list item related data is to be displayed on right hand side.
When I click on the list item, first time it works fine. It displays the task force name as a header in right hand side panel. When I click on another list item it gives TypeError: v2.CurrentTaskForce is not a function
var VirtualDir = GetVirtualDirectory();
angular.module('MyApp',[])
.controller('TaskForceController', function ($scope, TaskForceService) { // inject taskforce service
$scope.TaskForceList = null;
//$scope.CurrentTaskForce = {}
TaskForceService.GetTaskForceList().then(function (d) {
$scope.TaskForceList = d.data;
}, function () {
alert('failed');
});
$scope.CurrentTaskForce = function (item) {
angular.forEach($scope.TaskForceList, function (value, index) {
value.IsActive = false ;
})
item.IsActive = true;
alert("s");
$scope.CurrentTaskForce = item;
}
})
.factory('TaskForceService', function ($http) { //here factory is created which is a populer way to create and configure services
var fac = {};
fac.GetTaskForceList = function () {
return $http.get(VirtualDir + '/TaskForce/GetMyTaskForce/');
}
return fac;
});
<div class="container-fluid" ng-controller="TaskForceController as tf">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar" >
<%-- <li class="active">Overview <span class="sr-only">(current)</span></li>--%>
<li ng-repeat="item in TaskForceList" ng-class="{active: item.IsActive == true}" ng-click="CurrentTaskForce(item)" ><a href="#" >{{item.TaskForce}}</a></li>
</ul>
</div>
<div class="col-sm-9 co-md-9" style="left:20%">
<div class="panel panel-default" ">
<div class="panel-heading">
<p class="panel-title">{{CurrentTaskForce.TaskForce}}</p>
<!--ng-repeat="curritem in CurrentTaskForce"-->
</div>
</div>
</div>
</div>
</div>
While copying item to CurrentTask force instead of
$scope.CurrentTaskForce = item;
I used
angular.copy(item, $scope.CurrentTaskForce);
It is happening because CurrentTaskForce is defined as a function and a variable in same controller. Please use a different name for either.
I have an ng-class function which add the class 'Selected' through a toggle function. I want to remove ALL the items classes that have this 'Selected' class when this function runs.
controller.js
$scope.addItemToggle = function(item) {
item.selected = !item.selected;
if (item.selected) {
$scope.items.push({
itemName: item.itemName,
itemIcon: item.itemIcon,
});
} else {
var index = $scope.items.indexOf(item);
$scope.items.splice(index, 1);
}
};
view.html
<ul class="outfit-icons row">
<li class="outfit-button col-33" ng-repeat="item in clothing" ng-class="{'selected':item.selected}" ng-click="addItemToggle(item)">
<div class="item-tick">
<i class="ion-android-done"></i>
</div>
</li>
</ul>
You can pass an index parameter to your function :
<ul class="outfit-icons row">
<li class="outfit-button col-33" ng-repeat="item in clothing" ng-class="{'selected':item.selected}" ng-click="addItemToggle(item, $index)">
<div class="item-tick">
<i class="ion-android-done"></i>
</div>
</li>
</ul>
$scope.addItemToggle = function(item, index) {
$scope.items.forEach(function (item, i) {
if (i !== index) {
item.selected = false;
}
});
if (item.selected) {
$scope.items.push({
itemName: item.itemName,
itemIcon: item.itemIcon,
});
} else {
var index = $scope.items.indexOf(item);
$scope.items.splice(index, 1);
}
};
I have the following layout:
<nav ng-include="'views/nav.html'"></nav>
<div class="container-fluid">
<div ng-view></div>
</div>
Inside nav.html I want to display a dropdown link, once someone has entered a page, and has access. This page is rendered in the ng-view div
Right now I am using a service to update the shared value from one controller to the nav controller. However, the value is never updated in the nav controller. It is set in the service, but not updated.
<nav class="navbar navbar-inverse" role="navigation" ng-controller="LoginController as login">
<div class="container-fluid">
<ul class="nav navbar-nav">
<li>Show option '{{login.showOption}}' <span class="glyphicon glyphicon-info-sign"></span></li>
<li ng-if="login.showOption" dropdown>
<a href class="dropdown-toggle" dropdown-toggle>
Options <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a ng-href>1</a></li>
<li><a ng-href>2</a></li>
</ul>
</li>
</ul>
</div>
</nav>
LoginController.js
var LoginController = function (Option) {
var model = this;
model.showOption = Option.getValue();
module.controller("LoginController", ['Option', LoginController]);
}(angular.module("myApp")));
Option.js
'use strict';
(function (module) {
var option = function () {
var value = false;
return {
getValue: function() {
return value;
},
setValue: function(newVal) {
value = newVal;
}
};
};
module.service("Option", option);
}(angular.module("civApp")));
I am updating the Option.getValue() from another controller in another view, however the nav isn't getting updated.
GameController.js
var GameController = function (Option) {
Option.setValue(true);
module.controller("GameController", ['Option', GameController]);
}(angular.module("myApp")));
When I call this code, the view in the nav.html is not updated. I can see that the Option service is called, but I was hoping the value would have been updated in the view also.
GameController
LoginController
Nav.html
I can clearly see in GameController#watch that the Option.value:show is correctly set to true
That can be sorted using by angular dot rule
just update your code to :
Option Service
(function (module) {
var option = function () {
//value.show instead value
var value = {
show: false
};
return {
value: value
};
};
module.service("Option", option);
}(angular.module("civApp")));
and after that in your controllers
Login
var LoginController = function (Option) {
var model = this;
model.showOption = Option.value;
module.controller("LoginController", ['Option', LoginController]);
}(angular.module("myApp")));
GameController
var GameController = function (Option) {
Option.value = {
show: true
};
module.controller("GameController", ['Option', GameController]);
}(angular.module("myApp")));
and finally in your view
<li>Show option '{{login.showOption.show}}' <span class="glyphicon glyphicon-info-sign"></span>