I currently have a repeated list repeating category names from my JSON data. Each li is it's own repeated list of people related to that category (see CodePen) What I want to do is open a div under the current nested li displaying data regarding the individual clicked. My demo has it working except it opens under EACH li instead of the current one. I know there is probably a solution similar to the select(i) i have in the demo but can't quite get it to work. Any help would be appreciated.
My HMTL:
<div data-ng-app="app" data-ng-controller="starWarsCtrl">
<ul>
<li data-ng-repeat="cat in getCategories()">
<h2>{{cat}}</h2>
<div ng-click="select(i)" ng-repeat="i in data | filter:{cat: cat}">
<p>{{i.name}}</p>
</div>
</li>
</ul>
</div>
My AngularJS:
angular.module('app', ['ngAnimate'])
.controller('starWarsCtrl', function ($scope) {
$scope.data = [
{"name": "Obi-Wan Kenobi",
"index":88,
"cat": "jedi"},
{"name": "Yoda",
"index":69,
"cat":"jedi"},
{"name": "Lando",
"index":31,
"cat": "smuggler"},
{"name": "Han Solo",
"index":90,
"cat": "smuggler"},
{"name": "Darth Vader",
"index":98,
"cat": "sith"},
{"name": "Jar-Jar Binks",
"index":80,
"cat": "alien"},
{"name": "Mace Windu",
"index":45,
"cat": "jedi"},
{"name": "Chewy",
"index":76,
"cat": "smuggler"}
];
$scope.select = function (item) {
$scope.selectedItem = item;
}
$scope.getCategories = function() {
var categories = [];
angular.forEach($scope.data, function(item) {
//item.cat is a string
if (categories.indexOf(item.cat) == -1) {
categories.push(item.cat);
}
});
return categories;
}
})
The quick answer is adding
&& cat === selectedItem.cat
to your data-ng-if. This checks whether the cat & selectedItem are matching appropriately.
Related
I have a simple ul and li tags which contains state and capitals, here I need to get all the data from json dynamically and to append into main div of class "details",Here I just hardcoded but actually it should come from json given below in the same way.Here is the code below
HTML
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="details">
<ul>
<li>state</li>
<li>
<ul>state1</ul>
<ul>state2</ul>
</li>
<li>capital</li>
<li>
<ul>capital1</ul>
<ul>capital2</ul>
</li>
</ul>
</div>
jquery
$(document).ready(function () {
$.ajax({
type: "GET",
url: "sample.json",
success: function(result)
{
console.log(result);
}
});
});
json
{
"state": [{
"name": "state1"
},
{
"name": "state2"
}
],
"capital": [{
"name": "capital1"
},
{
"name": "capital2"
}
]
}
Word of warning: your proposed markup isn't valid (Error: Text not allowed in element ul in this context.). Even so, it sounds like it's the appropriate output for this task.
I'll assume your Ajax request is working and returns a valid JSON structure as the result variable.
Having handled set up, here's the code to generate your structure:
const result = {
"state": [
{"name": "state1"},
{"name": "state2"}
],
"capital": [
{"name": "capital1"},
{"name": "capital2"}
]
};
const root = document.createElement("ul");
document.querySelector(".details").appendChild(root);
for (const key in result) {
const title = document.createElement("li");
title.innerText = key;
root.appendChild(title);
const list = document.createElement("li");
root.appendChild(list);
for (const o of result[key]) {
const ul = document.createElement("ul");
ul.innerText = o.name;
list.appendChild(ul);
}
}
<div class="details"></div>
I have a custom directive that is holding an array of JavaScript objects.
The object is a little complex and lengthy but I will display something similar to point out my problem:
A JSON.stringify of this displays the following:
[
{
"Id": 1,
"Name": "John Doe",
"EMail": "john#doe.com"
},
{
"Id": 2,
"Name": "Jim Doe",
"EMail": "jim#doe.com"
},
{
"Id": 3,
"Name": "Jeff Doe",
"EMail": "jeff#doe.com"
}
]
I am further using ng-repeat to display the values in a tabular form on my HTML.
The values are coming from an API call that fetches them from a database.
I want to swap - say the entire Object with Id 1 with the entire Object with Id 3 so that during my tabular display I can see Id 3 object details first and Id 1 object details last, without breaking any functionality.
What would be the best possible solution to do this within the frontend itself?
How about just swapping them using a temp variable?
var arr = [{"Id":1,"Name":"John Doe","EMail":"john#doe.com"},
{"Id":2,"Name":"Jim Doe","EMail":"jim#doe.com"},
{"Id":3,"Name":"Jeff Doe","EMail":"jeff#doe.com"}]
var tmpObj = arr[0];
arr[0] = arr[2];
arr[2] = tmpObj;
If you want to reverse the array, use Array.prototype.reverse()
var app = angular.module("myApp", []);
app.controller("myController", function($scope) {
var arr = [
{
"Id": 1,
"Name": "John Doe",
"EMail": "john#doe.com"
},
{
"Id": 2,
"Name": "Jim Doe",
"EMail": "jim#doe.com"
},
{
"Id": 3,
"Name": "Jeff Doe",
"EMail": "jeff#doe.com"
}
];
$scope.array = arr.reverse();
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myController">
<div ng-repeat="item in array">
{{item.Id}} - {{item.Name}} - {{item.EMail}}
</div>
</div>
</div>
I have 2 button dropdowns working, via angular-dropdowns. When I click a language selection in one dropdown, I want to change the array (with that language) that displays in the other dropdown. Things work with hardcoded changes, but not with user clicks.
Being an Angular newbie, I'm not sure if a factory is the right way, but here's my code of the moment. Array contents are shortened. The controller for language selection is:
residenceApp.controller('languageController', [ '$scope', 'changeLanguage',
function( $scope, changeLanguage ) {
var languageChoices = [
{"text": "English", "val": "en"},
{"text": "Español", "val": "es"}
];
$scope.ddMenuOptions = languageChoices;
$scope.ddMenuSelected = {};
$scope.$watch('ddMenuSelected', function(newVal) {
if (newVal && newVal.text) {
changeLanguage(newVal.val);
//changeLanguage is a factory function that executes translate.use(langKey); to translate HTML elements. It works.
}
}, true); //end of $scope.watch()
}]);
The relevant HTML for the language selection button is:
<div id="leftOfMap" class="floatingSection" data-ng-controller="languageController">
<ul>
<li class="leftOfMapItem"><button id="languageButton" dropdown-menu="ddMenuOptions" dropdown-model="ddMenuSelected" class="btn-menu">{{ 'LANGUAGE' | translate }}</button></li>
The HTML for the second button is identical, except for the id and the name on the button.
The factory with dropdown arrays in several languages looks like:
languageFactories.factory( 'changePostDd', [ '$translate', function( translate ) {
var ddSelections = [];
var ddSelections_en = [
{"text": "RENT:", "val": "R"},
{"text": "SELL:", "val": "S"}
];
var ddSelections_es = [
{"text": "RENTAR:", "val": "R"},
{"text": "VENDER:", "val": "S"}
];
var langKey=translate.use(); //works on page load only
switch( langKey ) {
case "en":
ddSelections = ddSelections_en;
break;
case "es":
ddSelections = ddSelections_es;
break;
default:
console.log('There should not be a default failover.');
}
return ddSelections;
}]);
Among many things, I've tried $scope in the factory, and it broke the entire page. I tried the value() method and it did not work with clicks.
The controller for the second dropdown button is very similar to the first one, except it gets its array from the factory, instead of being hardcoded in the controller.
residenceApp.controller('postButtonController', ['$scope', 'changePostDd',
function ($scope, ddSelections) {
$scope.ddMenuOptions = ddSelections;
$scope.ddMenuSelected = {};
$scope.$watch('ddMenuSelected', function(newVal) {
if (newVal && newVal.text) {
// do stuff
}
In short, when the Espanol selection is clicked and newVal.val is set to es, I want the factory (or whatever) to switch() in ddSelections_es. Currently, ddSelections_en goes to the second dropdown button on page load, and when click changes are made on Espanol, the factory does not change the array for display at that second button. How do I make the array of ddSelections change?
You can do this in AngularJS in the following way. I am sure you can use the same in similar widget libraries. The key here is your ng-options is chosen with
ddSelectionsAllLangs[languageSelected.val]
You may use some function on the scope as well.
//this is your existing code - language choices
var languageChoices = [
{"text": "English", "val": "en"},
{"text": "Español", "val": "es"}
];
$scope.ddMenuOptions = languageChoices;
//if you want to default to certain language
$scope.languageSelected = languageChoices[0];
var ddSelections_en = [
{"text": "RENT:", "val": "R"},
{"text": "SELL:", "val": "S"}
];
var ddSelections_es = [
{"text": "RENTAR:", "val": "R"},
{"text": "VENDER:", "val": "S"}
];
$scope.ddSelectionsAllLangs = {
en: ddSelections_en,
es: ddSelections_es
}
Then in the HTML say this drop down menu selects the language.
<select ng-model="languageSelected" ng-options="lang.text for lang in languageChoices">
<option value="">-- choose language --</option>
</select>
The next drop down menu is the actual content.
<select ng-model="ddSelected"
ng-options="lang.text for lang in ddSelectionsAllLangs[languageSelected.val]">
</select>
Another option:- Using $rootScope.myLang instead of additional <select> to choose the language
languageFactories.factory( 'changePostDd', [ '$translate', '$rootScope', function( translate, $rootScope ) {
var ddSelectionsAllLangs = {
en: [
{"text": "RENT:", "val": "R"},
{"text": "SELL:", "val": "S"}
],
es: [
{"text": "RENTAR:", "val": "R"},
{"text": "VENDER:", "val": "S"}
]
};
var changePostDdFactory = {};
//returns an array appropriate to the language
changePostDdFactory.getDDSelections = function() {
return ddSelectionsAllLangs[$rootScope.myLang]
};
return changePostDdFactory;
}]);
I abandoned the effort to make a custom factory on the hunch that the $translate service in angular-translate could be made to work. It took a lot of learning about AngularJS and an embarrassing number of hours, but it finally works in 3 lines of code inside the controller's worker function. The working code is here:
Can't get $translate service from angular-translate to change dropdown array for ngDropdowns
bhantol, thank you for pointing me in the right direction to learn a lot.
Lets say using the following data I would like to create a treeview-like representation.
var demoData = [
{"name": "person1", "parent": ""},
{"name": "person2", "parent": "person1"},
{"name": "person3", "parent": "person1"},
{"name": "person4", "parent": "person2"},
{"name": "person5", "parent": "person3"}
];
The output should be something like this.
person1
|--person2
| |--person4
|--person3
|--person5
How would I do this with AngularJS. I know how to do this lets say in C# with a recursive function but cannot get my head around how to do this in AngularJS.
I have looked at other questions on SO but the data there was formatted in a different way so that the child entities were directly in the parent entity.
Generally (like in C#) you can achieve recursive call by using ng-include.
One node calls ng-include="'tree_item_renderer' for each child.
Something like:
<script type="text/ng-template" id="tree_item_renderer">
<span>
{{showNode(data)}}
</span>
<ul class="some" ng-show="data.show">
<li ng-repeat="data in data.nodes"
ng-include="'tree_item_renderer'" tree-node></li>
</ul>
</script>
And root call:
<ul>
<li ng-repeat="data in displayTree"
ng-include="'tree_item_renderer'"></li>
</ul>
The basic demo you can find here in Plunker
Trying to see if data in one array matches the data in another. I have an array of objects, like so -
var ProductsList =
[
{"Name": "Product A"; "Rating": "3"},
{"Name": "Product B"; "Rating": "2"},
{"Name": "Product C"; "Rating": "1"},
];
I then want to compare this product list with user selected values, which come in an array that I get based on the values they selected via checkboxes. So if they selected 1, 2, 3 - all products should be shown, if they selected 1 - then only product A is shown.
I tried to use $.grep to do the filtering but I'm running into an issue filtering via array values. Let's hard code the user filer to all values as an example.
userFilterArray.Rating = [1, 2, 3];
function filter(ProductsList, userFilterArray)
filteredList = $.grep(ProductList, function(n) {
return (n.Rating == userFilterArray.Rating);
});
Obviously this doesn't work as I'm comparing n.Rating which is a string to an array but I'm not sure how to compare the string to string in this case.
Would grep be the easiest way to do this? Should I use a combo of .each .each? Maybe neither?
After a bunch of syntax and other fixes, I think this is what you're after:
var ProductsList = [
{"Name": "Product A", "Rating": 3},
{"Name": "Product B", "Rating": 2},
{"Name": "Product C", "Rating": 1}
];
var userFilterArray = [1, 3];
function filter(list, filterArr) {
return $.grep(list, function(obj) {
return $.inArray(obj.Rating, filterArr) !== -1;
});
}
var filteredList = filter(ProductsList, userFilterArray)
console.log( filteredList );
DEMO: http://jsfiddle.net/vK6N9/