Angularjs change text according to true false status - javascript

I am making a box with ng-repeat here is the html
<div class="mission_box clearfix" ng-repeat="mission in missions">
<img src="images/tick_patch.png" class="expired_img">
<h2>{{mission.name}}</h2>
<p class="clearfix"><em>Win</em> <span><img src="images/crown.png"> {{mission.crownwin}} Crowns</span> <span><img src="images/voucher.png"> {{mission.voucherwin}} Voucher</span></p>
<div class="progress_box_outer clearfix">
<div class="progress_box">
<span style="width:{{100/mission.tasktotal*mission.taskdone}}%"></span>
</div>
<p class="progress_count">{{mission.taskdone}}/{{mission.tasktotal}}</p>
</div>
<div class="expiry_date">
<p>{{mission.expiry | missionexpire}}</p>
</div>
</div>
And here is the defined array in controller for this
$scope.missions = [
{'name':'3 Start Checkins', 'crownwin':'100', 'voucherwin':'flipkart','tasktotal':'4','taskdone':'3','expiry':'Expire on 25/06','isexpired':false,'iscompleted':true},
{'name':'3 Start Checkins', 'crownwin':'100', 'voucherwin':'flipkart','tasktotal':'4','taskdone':'2','expiry':'Expire on 25/06','isexpired':false,'iscompleted':true}
]
And filter i have created yet
.filter('missionexpire', function(){
return function(input){
if(input == true){
input = 'Completed'
} else {
input = input
}
}
})
In the above code you can see the last div in html with class .expiry_date i have defined filter in that.
What exactly i want is to change the text of {{mission.expiry}} if the status of {{mission.iscomplete}} is true.
Any help is appreciated. Thanks.

You could simply achieve this without a filter. Just use a conditional expression like
<p>{{mission.iscompleted === true?'Completed': mission.expiry}}</p>
angular.module('app', []).controller('AppController', function($scope) {
$scope.missions = [{
'name': '3 Start Checkins',
'crownwin': '100',
'voucherwin': 'flipkart',
'tasktotal': '4',
'taskdone': '3',
'expiry': 'Expire on 25/06',
'isExpired': false,
'iscompleted': true
}, {
'name': '3 Start Checkins',
'crownwin': '100',
'voucherwin': 'flipkart',
'tasktotal': '4',
'taskdone': '2',
'expiry': 'Expire on 25/06',
'isExpired': true,
'iscompleted': false
}, {
'name': '3 Start Checkins',
'crownwin': '100',
'voucherwin': 'flipkart',
'tasktotal': '4',
'taskdone': '2',
'expiry': 'Expire on 25/06',
'isExpired': false,
'iscompleted': false
}]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app">
<div ng-controller="AppController">
<div class="mission_box clearfix" ng-repeat="mission in missions">
<h2>{{mission.name}}</h2>
<p class="clearfix"><em>Win</em> <span>{{mission.crownwin}} Crowns</span> <span> {{mission.voucherwin}} Voucher</span>
</p>
<div class="progress_box_outer clearfix">
<div class="progress_box">
<span style="width:{{100/mission.tasktotal*mission.taskdone}}%"></span>
</div>
<p class="progress_count">{{mission.taskdone}}/{{mission.tasktotal}}</p>
</div>
<div class="expiry_date">
<p>{{mission.iscompleted === true?'Completed': (mission.isExpired === true ? 'Expired' : mission.expiry)}}</p>
</div>
</div>
</div>
</body>

If you want to achieve this by filter try this. From the filter you need to return anything.
.filter('missionexpire', function(){
return function(input, iscompleted){
if(iscompleted){
return 'Completed';
} else {
return input;
}
}
})
and
<div class="expiry_date">
<p>{{mission.expiry | missionexpire:misson.iscompleted}}</p>
</div>
var app = angular.module('myApp', []);
app.controller('MyCtrl',['$scope', function($scope){
$scope.missions = [
{'name':'3 Start Checkins', 'crownwin':'100', 'voucherwin':'flipkart','tasktotal':'4','taskdone':'3','expiry':'Expire on 25/06','isexpired':false,'iscompleted':true},
{'name':'3 Start Checkins', 'crownwin':'100', 'voucherwin':'flipkart','tasktotal':'4','taskdone':'2','expiry':'Expire on 25/06','isexpired':false,'iscompleted':true}
]
}])
app.filter('missionexpire', function(){
return function(input, isCompleted){
if(isCompleted){
return 'Completed';
} else {
return input;
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='myApp' ng-controller='MyCtrl'>
<div class="mission_box clearfix" ng-repeat="mission in missions">
<h2>{{mission.name}}</h2>
<p class="clearfix"><em>Win</em> <span>{{mission.crownwin}} Crowns</span> <span> {{mission.voucherwin}} Voucher</span>
</p>
<div class="progress_box_outer clearfix">
<div class="progress_box">
<span style="width:{{100/mission.tasktotal*mission.taskdone}}%"></span>
</div>
<p class="progress_count">{{mission.taskdone}}/{{mission.tasktotal}}</p>
</div>
<div class="expiry_date">
<p>{{mission.expiry | missionexpire:mission.iscompleted}}</p>
</div>
</div>
</div>

To filter content according to a specific property value in AngularJs there are used Pipes ( | )
So, in your section:
<div class="expiry_date">
<p>{{mission.expiry | missionexpire}}</p>
</div>
You add only the property but not the evaluation for that property. To do so you need to change that to,
<div class="expiry_date">
<p>{{mission.expiry | missionexpire:iscomplete}}</p>
</div>

Related

How can I render two object in div?

I have 2 objects with data and I need to restruct the rendering in html.
This is what I get:
but this is what I need to obtain:
Black box is the *ngFor of articles object, respectively red one is *ngFor of adsContainer object
<div *ngFor="let article of articles; let i = index;">
<mat-card class="card">
<div>
<a class="title">
{{article.title}}
</a>
<a>
<p>{{article.content}}</p>
</a>
</div>
</mat-card>
<div class="container" *ngIf="(i % 7) === 6">
<div *ngFor="let data of adsContainer">
<div>
<h1>{{data.value}}</h1>
</div>
</div>
</div>
</div>
public adsContainer: any = [
{ id: '1', value: 'text value here' },
{ id: '2', value: 'text value here' },
{ id: '3', value: 'text value here' }
]
public articles: any = [
{ id: '1', title: 'title value here', content: 'content here' },
{ id: '2', title: 'title value here', content: 'content here' },
{ id: '3', title: 'title value here', content: 'content here' },
........
{ id: '20', title: 'title value here', content: 'content here' },
]
Your issue is that you add your ads containers in a loop
<div class="container" *ngIf="(i % 7) === 6">
<!-- this loop here -->
<div *ngFor="let data of adsContainer">
<div>
<h1>{{data.value}}</h1>
</div>
</div>
</div>
what you want is to add only one ad container at a time, in order to do that, you have to rmove the loop
In order to have the three ads show, you'll have to do some math to get the ad index from the article index
something like this :
<div class="container" *ngIf="(i % 7) === 6">
<div>
<h1>{{adsContainer[mathFloor(i / 7)].value}}</h1>
</div>
</div>
note that Math is not available in angular templates, you'll have to redefine floor as a component method
function mathFloor(val) {return Math.floor(val)}
Try to use directly the array , also when you call
adsContainer[(parseInt(i / 6)-1)% adsContainer.length, it will always restart the index:
<div *ngFor="let article of articles; let i = index;">
<mat-card class="card">
<div>
<a class="title">
{{article.title}}
</a>
<a>
<p>{{article.content}}</p>
</a>
</div>
</mat-card>
<div class="container" *ngIf="(i % 7) === 6">
<div>
<div>
<h1>{{adsContainer[(parseInt(i / 6)-1)%adsContainer.length].value}}</h1>
</div>
</div>
</div>
</div>

data-ng-repeat with different tags in Angular

There is the following variable in Angular controller:
$scope.items = [
{ title: 'x', type: 'x'},
{ title: 'y', type: 'y'}
];
You can see only 2 items in array, but they will be more. So, I need to 'render' this array in HTML. I can use ng-repeat Angular directive, but there is some problem: if item has type 'x' I must render for it, if y - for it. How can I do it? Thanks in advance!
Place a :filter in the ng-repeat, like this:
var app = angular.module('myapp', []);
app.controller('myctrl', function($scope) {
$scope.items = [{
title: 'x',
type: 'x'
}, {
title: 'y',
type: 'y'
}, , {
title: 'another x',
type: 'x'
}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myapp" ng-controller="myctrl">
<div>Only items of type 'x':</div>
<ul>
<li ng-repeat="item in items | filter: {type: 'x'} ">{{item.title}}</li>
</ul>
</div>
Use a commbination of ng-repeat and ng-switch:
angular.module('myApp', [])
.controller('myCtrl', function($scope) {
$scope.items = [
{ title: "TestX", type: "x" },
{ title: "TestY", type: "y" }
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="item in items">
{{ item.title }}
<div ng-switch="item.type">
<div ng-switch-when="x">
HTML for type x
</div>
<div ng-switch-when="y">
HTML for type y
</div>
</div>
</div>
</div>
You can also use ng-hide which hides element if expression is true
<div ng-repeat="item in items" >
<div ng-hide="item.type == 'y'">
{{ item.type }}
</div>
<div ng-hide="item.type == 'x'">
{{ item.type }}
</div>
</div>
If you want to render only for item type x then can user 'filter' in ng-repeat or can use ng-if
<div ng-repeat="item in items">
<div ng-if="item.type==='x'">
<p>Item for type x</p>
</div>
</div>

Strange behaviour when Ordering by dynamic count AngularJS -

I want to order this list of exercises by count, this works on first load, but when you start to click the increase or decrease, it increases/decreases the count of other indexes
HTML:
<div class="row" ng-repeat="exercise in exercises | orderBy:'count' ">
<div class="exercise-icon col-xs-2"> <img ng-src="{{ exercise.icon }}" /></div>
<div class="col-xs-6">
<p class="exercise-name"> {{ exercise.name }} </p>
</div>
<div class="col-xs-4 counters">
<span class="decrease" ng-click="decrease($index)">-</span>
<span class="count">{{ exercise.count }} </span>
<span class="increase" ng-click="increase($index)">+</span>
</div>
</div>
JS - Controller
app.controller('MainController', ['$scope', function($scope) {
$scope.exercises = [
{
icon: 'img/pushup.jpg',
name: 'Pushups',
count: 20
},
{
icon: 'img/squat.jpg',
name: 'Squats',
count: 15
},
{
icon: 'img/pullup.jpg',
name: 'Pullups',
count: 10
},
...
$scope.increase = function(index) {
$scope.exercises[index].count += 1;
};
$scope.decrease = function(index) {
if ( ($scope.exercises[index].count) > 0){
$scope.exercises[index].count -= 1;
}
};
Instead using $index pass object itself
Like this
<span class="decrease" ng-click="decrease(exercise)">-</span>
JS
$scope.decrease=function(exercise){
exercise.count--;
}

Using another scope object values within the ng-repeat of some other scope object

I have set up a fiddle to explain my question well. I would like to display the names from the $scope.gem inside ng-repeat [only one name for each ng-repeat and don't loop all] of $scope.knobItems without extending the knobItems scope. I want this to be made possible by maintaining the exact structure of controller as it is now. I am new to angular. I just wanna know if this is possible in angular and if is a good practice.
view
<div ng-app="myapp">
<div ng-controller="Mycont">
<div ng-repeat="knobs in knobItems">
<div ng-repeat="(key, value) in knobItems.nums">{{value.knobTitle}} : {{value.knobColor}}
<div ng-bind="gem[0].name"></div>
</div>
</div>
</div>
</div>
controller
var ngMod = angular.module("myapp", []);
ngMod.controller("Mycont", function ($scope) {
$scope.knobItems = {};
$scope.knobItems.nums = [{
knobTitle: "Company Profile",
knobColor: "#f46607"
}, {
knobTitle: "Deals left This Month",
knobColor: "#ffcc00"
}, {
knobTitle: "Pricelist",
knobColor: "#f40787"
}, {
knobTitle: "Pictures",
knobColor: "#a1b80a"
}, {
knobTitle: "Videos",
knobColor: "#14b9d6"
}];
$scope.gem = [{
name: "Thomas"
}, {
name: "Sebastian"
}, {
name: "June"
}, {
name: "Yuvan"
}];
});
intended output
Easy fix: fiddle
<div ng-app="myapp">
<div ng-controller="Mycont">
<div ng-repeat="knobs in knobItems">
<div ng-repeat="(key, value) in knobItems.nums">{{value.knobTitle}} : {{value.knobColor}}
<div ng-bind="gem[$index].name"></div>
</div>
</div>
</div>
</div>
The output in you fiddle is exactly the same without the first ng-repeat: http://jsfiddle.net/2nrbrfxL/
Going by you description rather than you code:
<div ng-app="myapp">
<div ng-controller="Mycont">
<div ng-repeat="knobs in knobItems">
<div ng-repeat="(key, value) in knobs">{{value.knobTitle}} : {{value.knobColor}}
<div ng-repeat="gemItem in gem">{{gemItem.name}}</div>
</div>
</div>
</div>
</div>
http://jsfiddle.net/p2fuq2du/
<div ng-app="myapp">
<div ng-controller="Mycont">
<div ng-repeat="(key, value) in knobItems.nums">{{value.knobTitle}} : {{value.knobColor}}
<div ng-bind="gem[key].name"></div>
</div>
</div>
</div>

Isolate just the element that was clicked

I'm just getting started with Angular and running up against some roadblocks in my understanding of certain core concepts. To better familiarize myself with this new framework I'm attempting to build a trivial application: "Would You Rather?". I present the user two questions, they pick one, I highlight their choice, and show how many votes each question has from previous users.
It sounds simple but I'm still stuck in a jQuery frame of mind; I want to select the element based on $(this) or $("#id").
I have a factory with an array of question objects. Each object has a firstQuestion and secondQuestion key that maps to a question, as well as a firstVotes and secondVotes key with the corresponding number of votes. I'm using a QuestionsCtrl to control scope and take action when a user makes a choice.
Here's my index.html file:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8">
<title>Would You Rather?</title>
<link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div class="container" ng-app="wouldYouRatherApp">
<div ng-controller="QuestionsCtrl">
<div class="container">
<div class="row text-center">
<h1 class="col-md-12">Would you rather...</h1>
</div>
<div class="row text-center">
<div class="col-md-12">
<h2 class="btn btn-lg btn-{{buttonClass}}" ng-click="recordAnswer('first')">{{question.firstQuestion}}</h2>
<span class="badge" ng-show="badge.show">{{question.firstVotes}}</span>
</div>
</div>
<div class="row text-center">
<h3 class="col-md-12"><small>or</small></h3>
</div>
<div class="row text-center">
<div class="col-md-12">
<h2 class="btn btn-lg btn-{{buttonClass}}" ng-click="recordAnswer('second')">{{question.secondQuestion}}</h2>
<span class="badge" ng-show="badge.show">{{question.secondVotes}}</span>
</div>
</div>
<br>
<div class="row text-center">
<div class="col-md-12">
<h2 class="btn btn-lg btn-primary" ng-show="showNextQuestion" ng-click="nextQuestion()">Next Question <span class="glyphicon glyphicon-forward"></span></h2>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.min.js"></script>
<script type="text/javascript" src="./main.js"></script>
</body>
</html>
And here's my main.js file:
var app = angular.module("wouldYouRatherApp", []);
app.factory("Badges", function() {
return {show: false}
})
app.factory("Questions", function() {
var Questions = [{
firstQuestion: "Ride a horse?",
firstVotes: 101,
secondQuestion: "Ride a cowboy?",
secondVotes: 212
},
{
firstQuestion: "Kiss a frog?",
firstVotes: 13,
secondQuestion: "Lick a slug?",
secondVotes: 23
},
{
firstQuestion: "Play Monopoly?",
firstVotes: 12,
secondQuestion: "Play Risk?",
secondVotes: 17
}];
return Questions;
})
app.controller("QuestionsCtrl", function($scope, Badges, Questions) {
$scope.question = Questions.shift();
$scope.buttonClass = 'default';
$scope.showNextQuestion = false;
$scope.badge = Badges;
$scope.recordAnswer = function(choice) {
console.log("User chose: " + choice);
$scope.buttonClass = 'success';
// increment votes badge
$scope[choice+'Votes'] += 1;
Badges.show = true;
$scope.showNextQuestion = true;
}
$scope.nextQuestion = function() {
$scope.question = Questions.shift();
Badges.show = false;
$scope.buttonClass = 'default';
$scope.showNextQuestion = false;
}
})
A live example can be found here: http://jsfiddle.net/t99TL/2/
The app's expected behavior is as follows:
Two questions are presented to the user.
The user clicks on one of the buttons.
That question is highlighted. And the votes badge is incremented. Both votes badges are displayed.
A 'Next Question' button is presented to the user.
When he/she clicks on the 'Next Question' button, a new question is loaded.
I feel like I probably need to create a directive for each individual question... but I'm not sure how to start, or if I'm even on the right path. Any advice on obstacles I'm going to face further down the line is much appreciated (i.e. Updating the votes attribute for the question, etc.).
There are a lot to change to make it work the way you want. This code is not perfect, just a demonstration.
HTML:
<div class="container" ng-app="wouldYouRatherApp">
<div ng-controller="QuestionsCtrl">
<div class="container">
<div class="row text-center">
<h1 class="col-md-12">Would you rather...</h1>
</div>
<div class="row text-center">
<div class="col-md-12">
<h2 class="btn btn-lg btn-{{question.firstQuestion.buttonClass}}" ng-click="recordAnswer(question.firstQuestion)">{{question.firstQuestion.text}}</h2>
<span class="badge" ng-show="badge.show">{{question.firstQuestion.votes}}</span>
</div>
</div>
<div class="row text-center">
<h3 class="col-md-12"><small>or</small></h3>
</div>
<div class="row text-center">
<div class="col-md-12">
<h2 class="btn btn-lg btn-{{question.secondQuestion.buttonClass}}" ng-click="recordAnswer(question.secondQuestion)">{{question.secondQuestion.text}}</h2>
<span class="badge" ng-show="badge.show">{{question.secondQuestion.votes}}</span>
</div>
</div>
<br>
<div class="row text-center">
<div class="col-md-12">
<h2 class="btn btn-lg btn-primary" ng-show="showNextQuestion" ng-click="nextQuestion()">Next Question <span class="glyphicon glyphicon-forward"></span></h2>
</div>
</div>
</div>
</div>
JS:
var app = angular.module("wouldYouRatherApp", []);
app.factory("Badges", function() {
return {show: false}
})
app.factory("Questions", function() {
var Questions = [{
firstQuestion: {
text:"Ride a horse?",
votes: 101,
buttonClass : 'default'
},
secondQuestion: {
text:"Ride a cowboy?",
votes: 212,
buttonClass : 'default'
},
},
{
firstQuestion: {
text:"Kiss a frog?",
votes: 13,
buttonClass : 'default'
},
secondQuestion: {
text:"Lick a slug?",
votes: 23,
buttonClass : 'default'
}
},
{
firstQuestion: {
text:"Play Monopoly?",
votes: 12,
buttonClass : 'default'
},
secondQuestion: {
text:"Play Risk?",
votes: 17,
buttonClass : 'default'
}
}];
return Questions;
})
app.controller("QuestionsCtrl", function($scope, Badges, Questions) {
$scope.question = Questions.shift();
$scope.buttonClass = 'default';
$scope.showNextQuestion = false;
$scope.badge = Badges;
$scope.recordAnswer = function(choice) {
choice.buttonClass = 'success';
choice.votes++;
Badges.show = true;
$scope.showNextQuestion = true;
}
$scope.nextQuestion = function() {
$scope.question.firstQuestion.buttonClass = "default";
$scope.question.secondQuestion.buttonClass = "default";
$scope.question = Questions.shift();
Badges.show = false;
$scope.showNextQuestion = false;
}
})
DEMO

Categories

Resources