My markup:
<li active="active.search">search</li>
<li active="active.lists">lists</li>
<li active="active.find">find</li>
My code:
$scope.active = {
search: true
};
$scope.activate = function(li) {
$scope.active = {};
$scope.active[li] = true;
}
First - the item I've set to be highlighted, doesn't actually get highlighted by default, however they do work when clicked.
Secondly - I'm trying to use what is actually active via:
if ($scope.active[0].search === true) {
... some values
}
Is this not correct? as I can't seem to make this work.
active isn't an angular directive so you need to enclose the variable in angular brackets {{ }} like
active="{{active.search}}"
for angular to parse it.
Related
I'm trying to figure out how to display up to 10 options from a suggestions array and then give the user the ability to select the option, with that option now becoming the search query?
Html and AngularJS:
<ul class="suggestions" ng-show="showAutocomplete">
<li ng-repeat="suggestion in autocomplete.suggestions" ng-show="suggestion.options.length > 0" ng-mousedown="searchForSuggestion()"><small>Searching —</small>
{{suggestion.options[0].text}}//how to display up to 10 options
</li>
</ul>
Suggestions array
$scope.autocomplete = {
suggestions: []
};
$scope.showAutocomplete = false;
JS:
$scope.searchForSuggestion = function() {
$scope.searchTerms = $scope.autocomplete.suggestions[0].options[0].text;
$scope.search();
$scope.showAutocomplete = false;
};
More JS:
var getSuggestions = function(query) {
searchService.getSuggestions(query).then(function(es_return) {
var suggestions = es_return.suggest.phraseSuggestion;
if (suggestions.length > 0) {
$scope.autocomplete.suggestions = suggestions;
}
else {
$scope.autocomplete.suggestions = [];
}
if (suggestions.length > 0) {
$scope.showAutocomplete = true;
}
else {
$scope.showAutocomplete = false;
}
});
};
Suggestions is an array mapped to the $scope.autocomplete object.
I'm using PhraseSuggestion from ES and options is an array within the PhraseSuggestion object. Text is the actual option from the options array within the PhraseSuggestion object.
I hope that makes it a bit clearer - I'm a bit new to AngularJS and still learning it.
UPDATE:
I should be able to include the functionality that I'm seeking in the getSuggestions function, right? Just adjusting the if statements a bit... then all it really comes down to is the display, how to display up to 10 suggestions in the options array
I think you might be looking to use a nested ng-repeat with a limitTo filter placed on it.
I've put together a plunker showing how you can use limitTo with an ng-click on your populated options here http://plnkr.co/edit/8Mh....
If selecting an option alters suggestions, that should be fine and update the view accordingly.
Hope that helps you out!
I have an ng-repeat where the first item needs to have the class selected, as well as clicking on each item then changes the selection.
<li ng-repeat="ticker in tickers"
data-ng-class="{'selected':$first}"
ng-click="selectTicker(ticker.ticker)">{{ticker.ticker}}</li>
^ This works to have the first item have the class of selected by default.
<li ng-repeat="ticker in tickers"
data-ng-click="toggleTicker.item = $index"
data-ng-class="{'selected':toggleTicker.item == $index}"
ng-click="selectTicker(ticker.ticker)">{{ticker.ticker}}</li>
^ Thanks to this question. The above works to add the class of selected based on click, but the first item is no longer selected by default.
My question is how to combine both? I've tried the following which did not work:
data-ng-class="{'selected':$first && toggleObject.item == $index}"
My controller:
var vs = $scope;
ApiFactory.getWatchList().then(function(data) {
vs.tickers = data.data.tickers;
vs.toggleTicker = {item: -1};
vs.toggleTicker.item = vs.tickers[0];
vs.loadingDone = true;
console.log(vs.tickers[0]);
});
You are initializing item to the object at index 0 in your controller, but everywhere else it seems to be a number. If you just want to use the index (as your click sets it to the number), then try this:
var vs = $scope;
ApiFactory.getWatchList().then(function(data) {
vs.tickers = data.data.tickers;
vs.toggleTicker = {item: 0}; // set index 0 as the selected index
vs.loadingDone = true;
//console.log(vs.tickers[0]); // what if there are no items?
});
html:
<li ng-repeat="ticker in tickers"
data-ng-click="toggleTicker.item = $index"
data-ng-class="{'selected':toggleTicker.item == $index}"
{{ticker.ticker}}
</li>
Using $first is bad because the same item will always be the first one (unless you re-order them). Using ng-click and data-ng-click is bad because they are essentially identical, maybe only one will actually get called?
That's not done in ng-class, but in the controller or ng-init:
data-ng-init="toggleObject.item = tickers[0]"
data-ng-class="{'selected':toggleObject.item == $index}"
I still suggest you do it in the controller.
I'm trying to filter collections of data using quicksand.js. However, I'm having problems getting my data to appear. I have been able to get the data to disappear. Yet, it won't re-appear. I've created a jsfiddle, which is available here. Basically, my JavaScript looks like this:
var $content = $('#stage');
var $data = $content.clone();
function filterData(tag) {
var data = [];
if (tag === null) {
data = $data.find('li');
} else {
data = $data.find('li[data-tags=' + tag + ']');
}
console.log(data);
$content.quicksand(data, {
duration: 800,
easing: 'easeInOutQuad'
});
return false;
}
Everything looks correct to me. I can't figure out what I'm doing wrong.
First, your fiddle is broken. One, you link quicksand 1.3 and pair it with a recent jquery version it doesn't support. Two, you call out the easeInOutQuad without linking the jquery.easing.1.3.js. Three, you have scope issues, the filterData function is not defined globally.
Your real problem, though, is this line in the documentation:
attribute – attribute containing unique value able to identify same item within source and destination collection, default: 'data-id'
None of your "stage" data lis have this attribute so it won't filter them properly. Add it and all seems to work:
<ul id="stage">
<li data-tags="A" data-id="1">Item A-1</li>
<li data-tags="A" data-id="2">Item A-2</li>
<li data-tags="B" data-id="3">Item B-1</li>
<li data-tags="B" data-id="4">Item B-2</li>
</ul>
Updated fiddle.
I am using Restangular in my AngularJS app. I have a table with a delete link for each item. I would like to delete the item and have the row automatically removed. But as things are it only deletes from DB. How can I refactor things so that it the DOM is updated automatically?
// The controller
angular.module('myApp').controller('ManageCtrl', function($scope, Restangular) {
$scope.delete = function(e) {
Restangular.one('product', e).remove();
};
Restangular.all('products').getList({}).then(function(data) {
$scope.products = data.products;
$scope.noOfPages = data.pages;
});
});
// The view
<li ng-repeat="product in products">
</li>
I would also love to find an example of this - even with Angular resource. All the admin/data table demos seem to work from static data.
According to Restangular https://github.com/mgonto/restangular#restangular-methods they mention that you should use the original item and run an action with it, so in your html code you should:
<li ng-repeat="product in products">
</li>
Then in your controller:
$scope.delete = function( product) {
product.remove().then(function() {
// edited: a better solution, suggested by Restangular themselves
// since previously _.without() could leave you with an empty non-restangular array
// see https://github.com/mgonto/restangular#removing-an-element-from-a-collection-keeping-the-collection-restangularized
var index = $scope.products.indexOf(product);
if (index > -1) $scope.products.splice(index, 1);
});
};
Notice they use the underscore.js without which will remove the element from the array. I guess that if they post that example in their readme page that means the .remove() function doesn't remove the original item from the collection. This makes sense, since not every item you remove you want removed from the collection itself.
Also, what happens if the DELETE $HTTP request fails? You don't want to remove the item then, and you have to make sure to handle that problem in your code.
In my case the above didn't quite work. I had to do the following:
$scope.changes = Restangular.all('changes').getList().$object;
$scope.destroy = function(change) {
Restangular.one("changes", change._id).remove().then(function() {
var index = $scope.changes.indexOf(change);
if (index > -1) $scope.changes.splice(index, 1);
});
};
I'm trying to create some tabs, one per profile the user chooses to save. Each profile is a ViewModel. So I thought I'd just create another ViewModel that contains an observableArray of objects of type: {name: profile_name, model: model_converted_to_json}.
I followed this example to create my code - but I get nothing bound, for some reason.
Here's my code:
-ViewModel (I use Requirejs, that explains the external wrapper):
"use strict";
// profiles viewmodel class
define(["knockout"], function(ko) {
return function() {
var self = this;
this.profilesArray = ko.observableArray();
this.selected = ko.observable();
this.addProfile = function(profile) {
var found = -1;
for(var i = 0; i < self.profilesArray().length; i++) {
if(self.profilesArray()[i].name == profile.name) {
self.profilesArray()[i].model = profile.model;
found = i;
}
}
if(found == -1) {
self.profilesArray().push(profile);
}
};
};
});
-The JS code (excerpt of larger file):
var profiles = new profilesViewMode();
ko.applyBindings(profiles, $("#profileTabs")[0]);
$("#keepProfile").on("click", function() {
var profile = {
name: $("#firstName").text(),
model: ko.toJSON(model)
};
profiles.addProfile(profile);
profiles.selected(profile);
console.log(profile);
$("#profileTabs").show();
});
-The HTML (Thanks Sara for correcting my HTML markup)
<section id="profileTabs">
<div>
<ul class="nav nav-tabs" data-bind="foreach: profilesArray">
<li data-bind="css: { active: $root.selected() === $data }">
</li>
</ul>
</div>
</section>
I have verified that the observableArray does get new, correct value on button click - it just doesn't get rendered. I hope it's a small thing that I'm missing in my Knockout data-bind syntax.
Thanks for your time!
You will want to call push directly on the observableArray, which will both push to the underlying array and notify any subscribers. So:
self.profilesArray.push(profile);
You are setting name using name: $('#firstName').text(); you may need to change that to .val() if this is referencing an input field (which I assumed here).
You are using .push() on the underlying array which bypasses ko's subscribers (the binding in this case)
Here is a working jsfiddle based on your code. I took some liberties with model since that wasn't included.