AngularJS: How to display an element on another div when clicked - javascript

I have an array of letters and I want to log whatever letter is clicked.
HTML:
<div class="col-md-2 col-sm-10 col-lg-1 letters"
ng-repeat="choice in images[num].letters track by $index">
<ul>
<li ng-click="displayLetter()"class="wordList">
{{choice}}
</li>
</ul>
</div>
JS:
$scope.displayLetter = function() {
console.log($scope.choice);
};
letters is stored inside an array of chars assigned to an object. The object is in an array of objects.
$scope.images =
[
{ pics: ["img/carrion.png", "img/telefrag.png", "img/thunder-skull.png", "img/skull-ring.png"], word: 'skull', length: 5,
letters: ['u', randLet(), randLet(), randLet(), 's', randLet(), 'k', 'l', randLet(), randLet(), randLet(), 'l' ]}
I keep getting undefined. How do I solve this?
I even tried adding an ng-model
<li ng-model="choice" ng-click="displayLetter()" class="wordList">
{{choice}}
</li>

The $scope is for the controller itself not for every single item in ng-repeat. Try it like this
<div class="col-md-2 col-sm-10 col-lg-1 letters">
<ul>
<li ng-repeat="choice in images[num].letters track by $index" ng-click="displayLetter(choice)" class="wordList">
{{choice}}
</li>
</ul>
</div>
$scope.displayLetter = function(choice) {
console.log(choice);
};
And as Lex mentioned below if you want each choice to be an li then the ng-repeat should on li. If you 4 elements in array and have the ng-repeat in the div you would get 4 div instead of 4 li.

I do not know if I quite understand your question.
But you could do the following:
file.js
var app = angular.module('test', []);
app.controller('maincontroller', function($scope) {
$scope.displayLetter = function(clicked) {
console.log(clicked);
};
$scope.images = [{
"pics": [
"http://www.aviacaobr.com.br/wp/img.png",
"http://www.psf.gov.pk/images/icons/gallery.png",
"http://handicrafts.nic.in/dc_hc_photo_gallery.png"
],
"word": 'skull',
"length": 5,
"letters": [
'u',
randLet(),
randLet(),
randLet(),
's',
randLet(),
'k',
'l',
randLet(),
randLet(),
randLet(),
'l'
]
}];
function randLet(){
return 'a';
}
});
file.html
<li><body ng-controller="maincontroller">
<div class="col-md-2 col-sm-10 col-lg-1 letters"
ng-repeat="choice in images[0].letters ">
<ul>
<li ng-click="displayLetter(choice)" class="wordList">
{{choice}}
</li>
</ul>
</div>
The function displayLetter receive a parameter, that is the clicked item.
And in ng-repeat, when ng-click call displayLetter pass the clicked item.
See in Plunker: Click Here

Related

Pass Multidimensional Array Elements to Div in Js

I have looked and haven't found any solutions to my issue.
I have a grid like a puzzle.
<div id="grid-container">
<div class="item" id="item1"></div>
<div class="item" id="item2"></div>
<div class="item" id="item3"></div>
<div class="item" id="item4"></div>
<div class="item" id="item5"></div>
<div class="item" id="item6"></div>
<div class="item" id="item7"></div>
<div class="item" id="item8"></div>
<div class="item" id="item9"></div>
<div class="item" id="item10"></div>
<div class="item" id="item11"></div>
<div class="item" id="item12"></div>
<div class="item" id="item13"></div>
<div class="item" id="item14"></div>
<div class="item" id="item15"></div>
<div class="item" id="item16"></div>
<div class="item" id="item17"></div>
<div class="item" id="item18"></div>
<div class="item" id="item19"></div>
<div class="item" id="item20"></div>
<div class="item" id="item21"></div>
<div class="item" id="item22"></div>
<div class="item" id="item23"></div>
<div class="item" id="item24"></div>
<div class="item" id="item25"></div>
<div class="item" id="item26"></div>
<div class="item" id="item27"></div>
<div class="item" id="item28"></div>
<div class="item" id="item29"></div>
<div class="item" id="item30"></div>
<div class="item" id="item31"></div>
<div class="item" id="item32"></div>
<div class="item" id="item33"></div>
<div class="item" id="item34"></div>
<div class="item" id="item35"></div>
<div class="item" id="item36"></div>
</div>
and I have an array of what I want to fill the puzzle with:
var ws = [
['A', 'P', 'P', 'L', 'E', 'P'],
['A', 'G', 'C', 'A', 'A', 'I'],
['A', 'R', 'A', 'A', 'A', 'Z'],
['A', 'A', 'A', 'A', 'T', 'Z'],
['P', 'P', 'A', 'A', 'A', 'A'],
['A', 'E', 'P', 'R', 'A', 'Y']
];
I have also created class to print out the array.
class Puzzle {
constructor(width, height) {
this.width = (width)? width : 6;
this.height = (height)? height : 6;
if(this.width != this.height)
throw "height and width must be the same"
}
print(){
console.log(ws)
}
}
puz = new Puzzle(6, 6);
puz.print();
What I want to do is to pass the output of the array into each div with IDs: item1..36.
I have used
document.getElementById('myArray').innerHTML = ws;
to try to get it to work but its not working. Please I need a better approach to it.
You may try this inside your print function. (my guess is your print will update the UI)
print() {
for(var i =1 ; i<= this.height; i++){
for(var j = 1; j <= this.width; j++) {
document.getElementById(`item${(i-1) * this.height + j}`).innerHTML = ws[i-1][j-1];
}
}
}
Hope this will help!
you need to create a matrix on the contructor,
class Puzzle {
constructor(width, height) {
var ws = [
['A', 'P', 'P', 'L', 'E', 'P'],
['A', 'G', 'C', 'A', 'A', 'I'],
['A', 'R', 'A', 'A', 'A', 'Z'],
['A', 'A', 'A', 'A', 'T', 'Z'],
['P', 'P', 'A', 'A', 'A', 'A'],
['A', 'E', 'P', 'R', 'A', 'Y']
];
if(this.width != this.height)
throw "height and width must be the same"
}
print(){
console.log(this)
}
}
puz = new Puzzle(6, 6);
now you can create a function that update the page and put values on elements:
you put all items on an 1D array
and then iterate items with 2 for cycle:
function updatePage(var x){
var elements = document.getElementsByClassName("item");
var k = 0;
for(var i = 0; i < puzzle.height; i++){
for(var j = 0; j < puzzle.width; j++){
elements[k].innerHTML = x.grid[i][j];
k++;
}
}
}
and finally you can call your function to view grid elements on the page:
updatePage(puzz);

Splicing array nested within ng-repeat,

The array is structured like so
$scope.structure = {
sections: [{
id:0,
sectionItems: []
},{
id:1,
sectionItems: []
},{
id:2,
sectionItems: []
}]
};
I have a nested ng-repeat so I can show items within sectionItems[]
(Inside should be objects and one of the keys is Name - not relevant)
<div ng-repeat="sections in structure.sections" class="col-md-12">
<div class="panel panel-info">
<ul class="screenW-section">
<li class="col-xs-6" ng-repeat="item in sections.sectionItems"
ng-click="item.splice($index, 1)">
{{item.Name}}
</li>
</ul>
</div> </div>
I want to be able to remove items on click but the
ng-click="item.splice($index, 1)
Is not working no matter how I format it.
try this:
var app = angular.module("testApp", []);
app.controller('testCtrl', function($scope){
$scope.structure = {
sections: [{
id:0,
sectionItems: ['1','2','3']
},{
id:1,
sectionItems: ['11','21','32']
},{
id:2,
sectionItems: ['12','22','32']
}]
};
$scope.remove = function(sectionItems,index){
sectionItems.splice(index, 1);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="testApp" ng-controller="testCtrl">
<div ng-repeat="sections in structure.sections" class="col-md-12">
<div class="panel panel-info">
<ul class="screenW-section">
<li class="col-xs-6" ng-repeat="item in sections.sectionItems"
ng-click="remove(sections.sectionItems,$index)">
{{item}}
</li>
</ul>
</div> </div>
</div>
To remove an item you need to remove it from the array.
So, for example, you could do
ng-click="remove(sections.sectionItems, $index)"
in the view, and
$scope.remove = function(array, index) {
array.splice(index, 1);
}
in the controller...
You're calling splice on the item and not the array
ng-click="sections.sectionItems.splice($index, 1)"

Ng-repeat on integer value

I'm trying to use ng-repeat on a div which should contain a star image, each pie in the JSON has a rating property from 1-5, and I want to use this value to loop out x number of stars. I've got this working somewhat but it's flawed in the way that I can't re-sort the array and make the stars follow the correct item in the list since I'm using [$index] to track the iteration.
My solution is rather ugly as well since I'm creating arrays with as many index placeholders as the value of the rating property, and then pushing this into an array to loop out the appropriate number of images. I would like to have a more elegant solution.
How should I go about this problem without using [$index]?
Snippet of the JSON:
{"pies": [
...
{
"name": "Blueberry pie",
"imageUrl": "img/blueberrypie.png",
"id": "1",
"rating": "5", //Ng-repeat depending on this value
"description": "Blueberry pie is amazing."
},
...
]}
My controller:
pieShopApp.controller('shopCtrl', ['$scope', '$http', '$routeParams', function ($scope, $http, $routeParams) {
$scope.pieId = $routeParams.pieId,
$scope.sortingOptions = ['A-Z', 'Rating'],
$scope.sortingValues = ['name', 'rating'],
$scope.ratings = [],
$http.get('jsons/pies.json')
.success(function(data, status) {
$scope.pies = data;
for (i = 0; i < $scope.pies.pies.length; i++) {
switch ($scope.pies.pies[i].rating) {
case "1": $scope.ratings.push(["1"]); break;
case "2": $scope.ratings.push(["1", "2"]); break;
case "3": $scope.ratings.push(["1", "2", "3"]); break;
case "4": $scope.ratings.push(["1", "2", "3", "4"]); break;
case "5": $scope.ratings.push(["1", "2", "3", "4", "5"]); break;
}
}
console.log($scope.ratings);
})
.error(function(status) {
console.log(status);
})
}]);
The list which contains the pie items:
<div id="pie-list-wrapper">
<ul class="nav">
<a href="#/pies/pieid" ng-repeat="pie in pies.pies | filter:query | orderBy:orderProp">
<li class="list-item rounded-corners box-shadow">
<aside>
<img src="{{pie.imageUrl}}" no-repeat alt="Image of the pie">
</aside>
<header>
<h1 ng-bind="pie.name" id="item-name" class="bold-text"></h1>
</header>
<article>
<span ng-bind="pie.description" id="item-desc"></span>
</article>
<footer id="item-rating">
<div ng-repeat="rating in ratings[$index]" class="rating-box"></div> //Contains the stars
</footer>
</li>
</a>
</ul>
</div>
Outcome:
Checkout this
<div ng-app='myApp' ng-controller="Main">
<span ng-repeat="n in range('5')">Start{{$index}} </span>
</div>
$scope.range = function(count){
var ratings = [];
for (var i = 0; i < count; i++) {
ratings.push(i)
}
return ratings;
}
Change your html to following
<div id="pie-list-wrapper">
<ul class="nav">
<a href="#/pies/pieid" ng-repeat="pie in pies.pies | filter:query | orderBy:orderProp">
<li class="list-item rounded-corners box-shadow">
<aside>
<img src="{{pie.imageUrl}}" no-repeat alt="Image of the pie">
</aside>
<header>
<h1 ng-bind="pie.name" id="item-name" class="bold-text"></h1>
</header>
<article>
<span ng-bind="pie.description" id="item-desc"></span>
</article>
<footer id="item-rating">
<div ng-repeat="start in range(pie.rating)" class="rating-box"></div> //Contains the stars
</footer>
</li>
</a>
</ul>
</div>
I solved this in this way:
"items" is your array of objects in the $scope, accesing the property "rating", you can show the star if the value is less or the same comparing to the "rating" property.
In this example I'm using some icon fonts but for the case of an image is the same thing.
<div ng-repeat="item in items">
<div class="item-offers"">
<img ng-src="{{item.image}}">
<div class="item-not-rating">
<i class="icon ion-ios-star icon-rating" ng-if="item.rate >= 1"></i>
<i class="icon ion-ios-star icon-rating" ng-if="item.rate >= 2"></i>
<i class="icon ion-ios-star icon-rating" ng-if="item.rate >= 3"></i>
<i class="icon ion-ios-star icon-rating" ng-if="item.rate >= 4"></i>
<i class="icon ion-ios-star icon-rating" ng-if="item.rate >= 5"></i>
</div>
</div>
</div>
I've found a better solution that solves this requirement at all:
https://github.com/fraserxu/ionic-rating
It looks like you are iterating on the pies and that's where the $index gets its value from.
Instead of ng-repeat="rating in ratings[$index]"
you should use ng-repeat="rating in range(pie.rating)"
This way, the rating would follow your pie when ordering.
Then you could completely remove the loop in the controller.
Could you provide just a bit more HTML so that we could see where the $index comes from?
Regards,
Camusensei
EDIT:
You are indeed iterating over pies.pies in
ng-repeat="pie in pies.pies | filter:query | orderBy:orderProp"
So what I wrote earlier should work. See below for exhaustive changes.
Controller:
$http.get('jsons/pies.json')
.success(function(data, status) {
$scope.pies = data;
})
.error(function(status) {
console.log(status);
})
HTML:
<div ng-repeat="rating in range(pie.rating)" class="rating-box"></div>
EDIT2: Sorry, I forgot the range function (inspired from Ariya Hidayat):
$scope.range = function(count){
return Array.apply(0, Array(+count));
}
The problem is that ng-repeat only works with arrays or objects, so you can't say iterate x times (while x is a number)
A solution could be to write a function in JavaScript:
$scope.getNumber = function(num) {
return (new Array(num));
}
An then use this html to show the stars without $index:
<div ng-repeat="rating in getNumber(pie.rating)"></div>
In Angular 1.4+ you get the following error when using an empty array:
Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed.
The following works:
$scope.range = function(count) {
return Array.apply(0, Array(+count)).map(function(value,index){
return index;
});
}
<div ng-app='myApp' ng-controller="Main">
<span ng-repeat="n in range(5)">Start{{$index}} </span>
</div>

Using a {{expression}} inside ng-repeat to keep a count on ng-click

This throws a Syntax error. because of {{count}} inside of a ng-repeat.
I have a button that adds +1 to count:
Add count
Controller function:
$scope.count = 0;
$scope.addCount = function() {
$scope.count++;
alert($scope.count);
};
I would like this count to control the array index of a model::
$scope.img = [[
{
'src': 'runner-922.png',
'klass': 'h9'
},
{
'src': 'tweet.jpg',
'klass': 'h3'
}
],
{
'src': 'runner-922x.png',
'klass': 'h9'
},
{
'src': 'tweetx.jpg',
'klass': 'h3'
}
]
Which will be looped through using ng-repeat:
<div ng-repeat="i in img[{{count}}]" class="item {{i.klass}}" >
<img ng-src="images/iphone/{{i.src}}" alt="">
</div>
change this
<div ng-repeat="i in img[{{count}}]" class="item {{i.klass}}" >
<img ng-src="images/iphone/{{i.src}}" alt="">
</div>
to this
<div ng-repeat="i in img[count]" class="item {{i.klass}}" >
<img ng-src="images/iphone/{{i.src}}" alt="">
</div>
See this plunker

Recursive function for DOM to JSON

I'm trying to create a JSON index of a particular section of HTML. Here is the HTML that I have:
<div class="box span12">
<div class="row-fluid">
<div class="item span12" data-width-helper="12"></div>
</div>
<div class="row-fluid">
<div class="box span6">
<div class="row-fluid">
<div class="item span12" id="4" data-width-helper="12"></div>
</div>
<div class="row-fluid">
<div class="box span6">
<div class="row-fluid">
<div class="item span12" id="6" data-width-helper="12"></div>
</div>
<div class="row-fluid">
<div class="item span12" id="7" data-width-helper="12"></div>
</div>
</div>
<div class="item span6" id="5" data-width-helper="6"></div>
</div>
</div>
<div class="item span6" data-width-helper="6"></div>
</div>
<div class="row-fluid">
<div class="item span8" id="2" data-width-helper="8"></div>
<div class="item span4" id="3" data-width-helper="4"></div>
</div>
</div>
Ultimately, I'd like to end up with JSON that looks like this:
[
[
{
"id":1,
"width":12
}
],
[
{
"width":6,
"items":
[
[
{
"id":4,
"width":12
}
],
[
{
"width":6,
"items":
[
[
{
"id":6,
"width":12
}
],
[
{
"id":7,
"width":12
}
]
]
},
{
"id":5,
"width":6
}
]
]
},
{
"id":8,
"width":6
}
],
[
{
"id":2,
"width":8
},
{
"id":3,
"width":4
}
]
]
So basically, each box holds an array of rows, which holds an array of items, which are objects with a little descriptive information. I can't seem to wrap my head around a recursive function that will build out that json object so that there can be boxes instead of items going down unlimited levels.
Hopefully someone smarter than me can take the time to help out - I'd really appreciate it. And as a side note, I'm fine with using jQuery and/or Underscore.js
I'm not entirely sure how you want the function to work, so I just wrote a bit of psuedocode for you. The goal here was to make every tag into an array of its children, unless the tag was an item, in which case, it creates an object with "width" and "id" instead.
function toJSON(element)
var returnObject;
switch
case: item
returnObject = {
"id": elementId,
"width": elementWidth
};
break;
case: default
returnObject = [];
for each child
returnObject.push(toJSON(child));
break;
return returnObject;

Categories