Let's assume there is an array of categories. Contained within this array, for each category, there is a variable number of images. Additionally, each image has a sub-array of paths for varying sizes of each image. Listed below is an example.
$scope.categories = [
{ "id": 1, "name": "Fashion", "images": [
{ "id": 1, "paths": [
{ "id": 1, "pathThumb":"thumbnail_A.jpg"},
{ "id": 2, "pathFull":"full_size_A.jpg"}
]}
]},
{ "id": 2, "name": "Sunsets", "images": [
{ "id": 1, "paths": [
{ "id": 1, "pathThumb":"thumbnail_B.jpg"}
{ "id": 2, "pathFull":"full_size_B.jpg"}
]},
{ "id": 2, "paths": [
{ "id": 1, "pathThumb":"thumbnail_C.jpg"}
{ "id": 2, "pathFull":"full_size_C.jpg"}
]}
]}
];
I would like to use the AngularJS ngRepeat directive to loop through the above data to produce the following
<div class="item fashion">
<img src="thumbnail_A.jpg">
</div>
<div class="item sunset">
<img src="thumbnail_B.jpg">
</div>
<div class="item sunset">
<img src="thumbnail_C.jpg">
</div>
I assume it would look something like the following:
<div class="item {{category.name}}" ng-repeat="...">
<img src="{{category.image.path.pathThumb}}">
</div>
I am not sure how to loop through an array with sub-array and extract the appropriate data. Any help would be greatly appreciated.
Use like:
<div ng-repeat="item in categories">
<div ng-repeat="image in item.images">
<a ng-href="{{image.paths[1].pathFull}}">
<img ng-src="{{image.paths[0].pathThumb}}">
</a>
</div>
</div>
you should use a wrapper container in order to get subarray of categories..
HTML
<div ng-repeat="category in categories">
<div class="item {{category.name | lowercase}}" ng-repeat="image in category.images">
<a ng-href="{{image.paths[1].path}}">
<img ng-src="{{image.paths[0].path}}">
</a>
</div>
</div>
here I used dynamic class with ng-class and using lowercase filter to get lowercase version of name string as class...
using ng-src as src attribute of img is important here because sometimes given interpolate ({{something}}) cause fail to load resource, because of data is not fecthed...
same thing for ng-href...
here is PLUNKER...
Related
I have some json with below results
{
"module": [
{
"id": 1,
"title": "Module 1",
"type": "URL",
"size": 1,
"image": "https://localhost/image1.png"
},
{
"id": 2,
"title": "Module 2",
"type": "YOUTUBE",
"size": 2,
"image": "https://localhost/image2.png"
}
]
}
Now i want to render it on a page with some loop and conditional, like below
<template>
<section class="page-section homescreen mt-4">
<div class="container">
<div class="row">
<div class="col-lg-3" v-bind:key="data.index" v-for="data in modules" v-if="data.size == 1">
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
<div class="col-lg-6" v-bind:key="data.index" v-for="data in modules" v-if="data.size == 2">
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
</div>
</div>
</section>
</template>
<script>
export default {
data() {
return {
modules: [
{
"id": 1,
"title": "Module 1",
"type": "URL",
"size": 1,
"image": "https://localhost/image1.png"
},
{
"id": 2,
"title": "Module 2",
"type": "YOUTUBE",
"size": 2,
"image": "https://localhost/image2.png"
}
]
};
}
};
</script>
But instead of success, i got some error saying
5:99 error The 'modules' variable inside 'v-for' directive should be
replaced with a computed property that returns filtered array instead.
You should not mix 'v-for' with 'v-if' vue/no-use-v-if-with-v-for
8:99 error The 'modules' variable inside 'v-for' directive should be
replaced with a computed property that returns filtered array instead.
You should not mix 'v-for' with 'v-if' vue/no-use-v-if-with-v-for
Actually i want to create the <div class="col-lg-3"> part to be dynamic based on the json, if size:1 mean to have col-lg-3 and if size:2 mean to have col-lg-6
Any explanation and suggestion will be appreciated.
Thank you
eslint-plugin-vue was telling you to do this:
<div class="col-lg-3" v-bind:key="data.index" v-for="data in modules.filter(o=>o.size == 1)">
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
<div class="col-lg-6" v-bind:key="data.index" v-for="data in modules.filter(o=>o.size == 2)">
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
In your case, it can be simplified as
<div :class="'col-lg-'+data.size*3" v-bind:key="data.index" v-for="data in modules">
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
If it's essentially something with css classes, why don't you use v-bind:class or :class with your condition ?
https://v2.vuejs.org/v2/guide/class-and-style.html
But like said in the error message you'll certainly have to create a sub component and then use props on it
https://v2.vuejs.org/v2/guide/components-props.html
In case you have just two sizes:
You can use Computed Properties to achieve this requirement.
First, create two new computed properties like:
computed: {
modulesSize1: function() {
return this.modules.filter(x => x.size == 1)
},
modulesSize2: function() {
return this.modules.filter(x => x.size == 2)
}
}
Now, you can easily loop through computed properties modulesSize1 && modulesSize2 like:
<div class="row">
<div class="col-lg-3" v-bind:key="data.index" v-for="data in modulesSize1" >
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
<div class="col-lg-6" v-bind:key="data.index" v-for="data in modulesSize2" >
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
</div>
In case you have multiple sizes:
First, create a simple method like:
methods: {
getClass: function(size) {
return `col-lg-${size * 3}`
},
}
and then we can update template and use Class Bindings like:
<div :class="getClass(data.size)" :key="data.index" v-for="data in modules">
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
The v-if is essentially baked in to the v-for (if modules is empty nothing will render) so it's recommended not to use them in combination. If you need it for a separate condition, like you do here, then you'll have to move your v-for on to the <img> itself.
You also won't be able to use data.size this way so you'd have to use something like v-if="modules[0].size == 1" etc.
Edit
#Palash answer is probably the more efficient way to solve this.
Edit 2
#r0ulito and #xianshenglu also makes a really good point, if it's just a class issue, use v-bind.
I'm creating pokemon cards that take data from the API. How can I get the CSS of a particular card get applied to its respective card from the API directly just like the information which I've rendered using angular-js.
I'm done retrieving the data like name, description and image.I used angular-js directives to get the data.Similarly, the API consists of CSS styling for each of their respective cards.How can I get the CSS of a particular card get applied to its respective card from the API directly just like the information which I've rendered using angular-js.
JSON:
[{
"cardColors": {
"bg": "#47C67B",
"imgbg": "#80EDAC",
"tagbg": "#8edbae",
"text": "#ffffff",
"textbg": "#66CF91"
},
"description": "Bulbasaur is a small quadruped Pokemon that has turquoise skin with darker teal patches ",
"name": "Bulbasaur",
"sprite": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png",
"tag": "Grass"
}, {
"cardColors": {
"bg": "#f88321",
"imgbg": "#ffb047",
"tagbg": "#fab275",
"text": "#ffffff",
"textbg": "#f99847"
},
"description": "Pikachu is a Mouse Pokemon and the evolved form of
Pichu. Pikachu's tail is sometimes struck by lightning as it raises it to
check its surroundings.",
"name": "Pikachu",
"sprite": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/25.png",
"tag": "Electric"
}]
JS:
var app = angular.module('myApp', []);
app.controller('pokemonCtrl', function($scope, $http) {
$http.get("pokemondata.json").then(function (response) {
$scope.myData = response.data;
});
});
HTML:
<div class="container" ng-app="myApp" ng-controller="pokemonCtrl">
<div class="row">
<div class="col-sm-4" ng-repeat="x in myData">
<h4>{{x.name}}</h4><br/>
<p>{{x.description}}</p><br/>
<img class="cards" ng-src="{{x.sprite}}"><br/>
</div>
</div>
</div>
You should use ngStyle to apply styles from your controller data to your list elements. Something like:
<div class="row">
<div class="col-sm-4" ng-repeat="x in myData" ng-style="{'background-color': x.bg, color: x.text}">
<h4>{{x.name}}</h4><br/>
<p ng-style="{'background-color': x.textbg}">{{x.description}}</p><br/>
<img class="cards" ng-src="{{x.sprite}}"><br/>
</div>
</div>
I have a complex object as shown below:
$scope.document =
{
"GENERAL_FIELDS": {
"Source_Type": "custom",
"Annotations": [
"216/content/Factiva_CM_001/Proteins",
"216/content/Factiva_CM_001/Fact"
],
"Content": [
" Baculovirus; Budded virus; Ultrastructure; Cryo-EM;"
],
"Title": [
"Budded baculovirus particle structure revisited"
]
},
"stn": {
"Document_Type": [
"Journal",
"Article"
]
}
}
I want to display all the fields present in "GENERAL_FIELDS" and "stn". Fields' value can either be string or array of strings. If it is array, I further want to ng-repeat on it and display the content. Following is my html:
<div id="titsec" class="comdocdet" ng-repeat="(category, group) in document">
<div ng-repeat="(key, value) in group">
<div class="pTitle">
{{key}}
</div>
<div class="contdesc">
<div ng-if="Array.isArray(value)">
<div ng-repeat="v in value">
{{v}}
</div>
</div>
<div ng-if="!Array.isArray(value)">
{{value}}
</div>
</div>
</div>
</div>
But ng-if="Array.isArray(value)" is never true and array fields are being displayed in object form: ["Journal","Article"]. What am I missing ?
Or add this in your controller and leave rest like it is.
$scope.isArray = angular.isArray;
html would be like this :
<div ng-if="isArray(value)">
<div ng-repeat="v in value">
{{v}}
</div>
</div>
<div ng-if="!isArray(value)">
{{value}}
</div>
Instead of accessing a method on the Array object directly in the template, you should do in your controller. So for example:
<div ng-if="vm.isValueAnArray(value)">
// Some html
</div>
Your controller:
function isValueAnArray(val) {
return Array.isArray(val);
}
I haven't tested it, but logic should be in the controller, not in the template.
This is an issue of Scoping
The scope of the template is relative to $scope in the controller, so when it looks for Array, it will look for that in the controller scope (e.g. $scope.Array).
One option is to use ng-if="window.Array.isArray(value)". See the working example below.
Another option is to set $scope.Array = Array.prototype in the controller. That way there is no need to reference window before calling Array.isArray().
Another option is to create an alias for Array.isArray() in the controller scope:
$scope.isValueAnArray = Array.isArray;
Then call that function to determine if the value is an array.
angular.module('ang', [])
.controller('cont', function($scope) {
//use this to avoid referencing window in the template
//$scope.Array = Array.prototype;
$scope.document = {
"GENERAL_FIELDS": {
"Source_Type": "custom",
"Annotations": [
"216/content/Factiva_CM_001/Proteins",
"216/content/Factiva_CM_001/Fact"
],
"Content": [
" Baculovirus; Budded virus; Ultrastructure; Cryo-EM;"
],
"Title": [
"Budded baculovirus particle structure revisited"
]
},
"stn": {
"Document_Type": [
"Journal",
"Article"
]
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ang" ng-controller="cont">
<div id="titsec" class="comdocdet" ng-repeat="(category, group) in document">
<div ng-repeat="(key, value) in group">
<div class="pTitle">
{{key}}
</div>
<div class="contdesc">
<div ng-if="window.Array.isArray(value)">
<div ng-repeat="v in value">
{{v}}
</div>
</div>
<div ng-if="!window.Array.isArray(value)">
{{value}}
</div>
</div>
</div>
</div>
</div>
I have a simple angularjs app with a simple array in a controller.
(function () {
"use strict";
angular.module('stylistFormulas').controller('ServiceTypesCtrl', ServiceTypesCtrl);
function ServiceTypesCtrl() {
var vm = this;
vm.serviceTypes = [
{
"text": "Retouch",
"image": "serviceTypes/images/Retouch.jpg",
"id": "retouch"
},
{
"text": "All Over",
"image": "serviceTypes/images/AllOver.jpg",
"id": "allover"
},
{
"text": "Highlights/Lowlights",
"image": "serviceTypes/images/Highlight.jpg",
"id": "highlight"
},
{
"text": "Ombre, Balayage, Sombre",
"image": "serviceTypes/images/Balayage.jpg",
"id": "ombre"
}
]
};
}());
I want to display these records similar to bootstraps thumbnail, custom content example but using bootstraps grid with two columns for larger screens and 1 for xs.
i.e.
image image
Title of Image Title of image
image image
Title of Image Title of image
image
Title of Image
I have tried numerous examples I have found on the web with no luck. I usually get just one column or nothing but the layout without the data.
My latest attempt...
<div ng-repeat="serviceType in vm.serviceTypes">
<div class="row | $index % 3 == 0">
<div class="col-sm-6">
<div class="thumbnail">
<img ng-src="{{serviceType.image}}" />
<div class="caption">
<h3>{{serviceType.text}}</h3>
</div>
</div>
</div>
</div>
</div>
How can I display this data using the ng-repeat or something else?
Thanks
<div class="row | $index % 3 == 0"> instead
can you try with
<div ng-class="row | $index % 3 == 0">
Because you cant do manipulations inside a HTML attribute.
I for my stage have to modifie a web site for that i need angularjs i wanted to use the command ng-repeat to display some documentation but when i add ng-repeat in the div it "destroy" it and i cant figure out why...
So there is the code hope u can help me.
There is my js
App.controller('doccontroller', [ function(){
return {
scope: {},
restrict: 'A',
link: function ($scope){
$scope.docs = [
{
"id_section" : 0,
"description": "RANDOM STUFF",
"source": [
{
"python": "TEXTE",
"ruby": "TEXTE",
"javascript": "TEXTE"
}
]
},
{
"id_section" : 1,
"description": "RANDOM STUFF",
"source": [
{
"python": "TEXTE",
"ruby": "TEXTE",
"javascript": "TEXTE"
}
]
},
{
"id_section" : 2,
"description": "RANDOM STUFF",
"source": [
{
"python": "TEXTE",
"ruby": "TEXTE",
"javascript": "TEXTE"
}
]
}
]
}
}
}
])
`There is my route to "include" the controller
$routeProvider.when '/docs',
templateUrl : config.BaseHtml+'/Page/docs.html'
controller : 'doccontroller'
`
and to finish the html :)
<div id="api-docs">
<div id="methods">
<div class="languages">
<a class="language selected" data-lang="ruby" href="#">Ruby</a>
<a class="language" data-lang="python" href="#">Python</a>
<a class="language" data-lang="php" href="#">PHP</a>
</div>
<div>
<div class="method" id="intro">
<div class="method-section clearfix">
<div class="method-description" ng-repeat="doc in docs">
<h3>Introduction</h3>
<p>
{{doc.description}}
</p>
</div>
<div class="method-example">
<pre>
<code class="ruby"># All this code is just folololol
React.api_key = "In here goes your api key!"</code><code class="python"># All this code is just for demonstration purposes
react.api_key = "In here goes your api key!"</code><code class="php"># All this code is just for demonstration purposes
React::setApiKey("In here goes your api key!");</code>
</pre>
</div>
</div>
</div>
</div>
</div>
</div>
So to say it again, what i need to do is to fill create 1 div / id_section and to fill it with the
descrition for now.
Change:
ng-repeat="docs in docs"
to:
ng-repeat="doc in docs"
Also, in your code you have a call to {{ doc.des }}, which probably should be {{ doc.description }}