Can vuejs use in v-if - arrays

I want to use 'in' syntax in Vue.js v-if like Python.
However, it doesn't seem to be working.
If I want to know if an element is in an array, how can I edit the following code?
<div id="app">
<ol>
<li v-for="site in sites" v-if="site.name in fs">
{{ site.name }}
</li>
</ol>
</div>
<script>
new Vue({
el: '#app',
data: {
sites: [
{ name: 'Runoob' },
{ name: 'Google' },
{ name: 'Taobao' }
],
},
fs: [
'Google'
]
});
</script>

Yeah, so, the keyword in in javascript is only used to iterate over an array, or to check for index value, not to check if an element is contained into it.
You can use indexOf instead. In your example:
v-if="fs.indexOf(site.name) !== -1"

Related

ng-repeat inside ng-if rendering despite falsey ng-if expression

I have an ng-repeat that iterates over an array of objects. Each object has a type property and a contents array. Inside the ng-repeat, I would like to display the contents array different depending on the type of the object, so I am conditionally displaying content with an ng-if.
The problem is it appears the ng-repeat is executing and rendering regardless of if the ng-if is truthy or falsey, and that when ng-if is falsey that it's not removing the ng-repeat DOM elements.
I'm not sure if there's something wrong with the implementation, or if these angular directives aren't meant to be used quite like this - or if there's a better way to solve this problem in angular.
Below are the snippets, and here is a working plunker: http://plnkr.co/edit/FZQ5CM8UFOepNIHHuTD4?p=preview
The HTML:
<div ng-controller="FunkyCtrl as vm">
<div ng-repeat="thing in vm.twoThings">
<p ng-if="thing.type === 'apple'">
<span>Type: {{thing.type}}</span>
<ul>
<li ng-repeat="content in thing.contents">Food: {{content.stuff}}</li>
</ul>
</p>
<p ng-if="thing.type === 'dog'">
<span>Type: {{thing.type}}</span>
<ul>
<li ng-repeat="content in thing.contents">Guts: {{content.stuff}}</li>
</ul>
</p>
</div>
</div>
The script:
(function(angular) {
angular.module('funkyStuff', []);
angular.module('funkyStuff').controller('FunkyCtrl', FunkyCtrl);
function FunkyCtrl() {
var vm = this;
vm.twoThings = [
{
type: 'apple',
contents: [
{
stuff: 'apple slices'
},
{
stuff: 'juice'
}
],
},
{
type: 'dog',
contents: [
{
stuff: 'bones'
},
{
stuff: 'meat'
}
]
}
];
}
})(angular);
Expected Output:
Type: apple
Food: apple slices
Food: juice
Type: dog
Guts: bones
Guts: meat
Actual Output:
Type: apple
Food: apple slices
Food: juice
Guts: apple slices
Guts: juice
Food: bones
Food: meat
Type: dog
Guts: bones
Guts: meat
It's because your HTML is invalid. The ul element is not allowed inside p.
If you inspect the rendered HTML you will notice that the ul has been rendered outside the p (might depend on the browser implementation of course).
Replace p with for example div and you will get the result you expect.
Demo: http://plnkr.co/edit/pBVZ4jIJ5qzRsa8xZbud?p=preview
If you want to know which elements are allowed inside p you can find a good answer here.

angular js ng-class shows expression as class instead of processing it

I'm trying to make highlighted menu items by using angular js. I've read this question and tried implementing the anwser, but instead of angular evaluating the expression, it just shows it as the class name. I don't know what's going on.
I have the menu items listed as JSON, and the iterate trough it with ng-repeat. Once the list items are created, I want the angular to add a class of 'active', if the location url is the same as the link.href attribute of a menu item (it's a json attribute, not the html one).
Here's the relevant html:
<div class="header" ng-controller="NavbarController">
<ul>
<li ng-repeat="link in menu" ng-class="{ active: isActive({{ link.href }}) }"><a ng-href="{{ link.href }}">{{ link.item }}</a>
</li>
</ul>
</div>
and my controller:
.controller('NavbarController', function ($scope, $location) {
// navbar links
$scope.menu = [
{
item: 'PTC-Testers',
href: '#/PTC-Testers'
},
{
item: 'articles',
href: '#/articles'
},
{
item: 'PTC sites',
href: '#/sites'
},
{
item: 'account reviews',
href: '#/account_reviews'
},
{
item: 'forum',
href: '#/forum'
},
{
item: 'contact us',
href: '#/contact'
},
{
item: 'login',
href: '#/login'
}
]; // end $scope.menu
$scope.isActive = function (viewLocation) {
return viewLocation === $location.path();
};
});
This is the navbar part of a bigger project, and I tried only inserting the relevant code. If you need further info to understand the question properly, please let me know.
It should be ng-class="{'active' : isActive(link.href)}"
You didn't end the curly brace in ng-class and its better to put class name inside quotes

Angular Grouping Directive starting point

I'am trying to create a grouping and filtering mechanism with several predefined filters. I have a collection of undefined rules and some predefined grouping actions, for example "relativeDate" (today, tomorrow, yesterday, this week, ...), "boolean" or . The set of actions should be expandable.
I've managed to get this working in a controller. But I want to outsource this into a directive to get this working with other object collections. The Problem is: I need to specify the template of the list dynamically.
Imagine the following collections:
$scope.memosReceived = [
{ id: 1, from: 'Henry Ford', title: 'Want your Model T?', received: '2015-05-04T12:30:00', read: true },
{ id: 2, from: 'Oliver Newton', title: 'Look at this!', received: '2015-06-15T08:00:00', read: true }
...
];
$scope.memosSent = [
{ id: 1, to: 'Henry Ford', title: 'That is an old car', sent: '2015-05-04T12:35:21', read: true },
{ id: 2, to: 'Oliver Newton', title: 'Stop Spam', sent: '2015-06-15T08:01:47', read: false }
...
];
Now the markup should be like the following:
<div ng-controller="controller">
<h2>Received</h2>
<grouped-list ng-model="memosReceived" item-var="received" grouping-options="groupingReceived">
<h2>{{ received.title }} <sub>by {{ received.from }}</h2>
</grouped-list>
<h2>Sent</h2>
<grouped-list ng-model="memosSent" item-var="sent" grouping-options="groupingSent">
<h2>{{ sent.title }} <sub>to {{ sent.to }}</h2>
</grouped-list>
</div>
Options could be like:
$scope.groupingReceived = [
{ modelKey: 'received', action: 'relativeDate', options: { [.. passed to grouping action, like value->name mapping ..] },
{ modelKey: 'read', action: 'boolean', options: { [...] } }];
$scope.groupingSent = [
{ modelKey: 'sent', action: 'relativeDate', options: { [.. passed to grouping action, like value->name mapping ..] },
{ modelKey: 'read', action: 'boolean', options: { [...] } }];
The rendered HTML should look like this "PseudoHtml":
<div ng-controller="controller">
<h2>Received</h2>
<div class="grouped-list">
<div class="filter-section">
<button ng-click="openFilters = !openFilters>Open Filters</button>
<div class="filter-options" ng-hide="!openFilters">
<h4>Group by</h4>
[selectbox given group actions] [selectbox sort ascending or descending]
<h4>Filter by</h4>
[build filters by similar to group actions given filter actions]
</div>
</div>
<div class="group">
<div class="group-header">
<h3>Yesterday</h3>
</div>
<ul class="group-list">
<li ng-repeat="received in ngModel | customFilters">
<!-- something like transclusion starts here -->
<h2>{{ received.title }} <sub>by {{ received.from }}</h2>
<!-- something like transclusion ends here -->
</li>
</ul>
</div>
<div class="group">
<div class="group-header">
<h3>Last Week</h3>
</div>
<ul class="group-list">
<li ng-repeat="received in ngModel | customFilters">
<!-- something like transclusion starts here -->
<h2>{{ received.title }} <sub>by {{ received.from }}</h2>
<!-- something like transclusion ends here -->
</li>
</ul>
</div>
</div>
<h2>Sent</h2>
<div class="grouped-list">
[... same like above ...]
</div>
</div>
I am really struggeling how to achieve this behavior, where to store the several parts of the logic (e.g. the grouping actions, the custom filters) and how to transclude this correctly.
Maybe someone can give me a good starting point for that.
You could create a custom filter and call it from the controller of your directive.
Inside of this filter you can decide which filter action should be triggered by passing parameters to the filter.
I would call it from the controller instead of the template because there you can easier chain your filters.
Please have a look at the demo below or in this jsfiddle.
During adding my code to SO I've detected a bug (not displaying the item) in my code with a newer AngularJS version. Not sure what it is but with 1.2.1 it's working.
I'll check this later. Seems like a scoping issue.
angular.module('demoApp', [])
.filter('aw-group', function($filter) {
var filterMethods = {
relativeDate: function(input, action) {
console.log('relative date called', input);
return input; // do the translation to relative date here
},
filterByNumber: function(input, action, options) {
// if you need mor parameters
return $filter('filter')(input, options.number);
},
otherFilter: {
}
};
return function(input, action, options) {
return filterMethods[action](input, action, options);
};
})
.directive('groupedList', function () {
return {
restrict: 'E',
scope: {
model: '=',
itemVar: '=',
filter: '='
},
transclude: true,
template: '<ul><li ng-repeat="item in filteredModel" ng-transclude>'+
'</li></ul>',
controller: function($scope, $filter) {
//console.log($scope.filter);
$scope.filteredModel = $filter('aw-group')($scope.model, 'filterByNumber', { number: 2 }); // passing action from $scope.filter.action as second parameter, third is an options object
}
};
})
.controller('mainController', function () {
this.data = [{
title: 'Test1',
from: 'tester1'
}, {
title: 'Test2',
from: 'tester1'
}, {
title: 'Test3',
from: 'tester1'
}, ];
this.groupingReceived = [{
modelKey: 'received',
action: 'relativeDate',
options: {},
modelKey: 'read',
action: 'boolean',
options: {}
}];
this.memosReceived = [{
id: 1,
from: 'Henry Ford',
title: 'Want your Model T?',
received: '2015-05-04T12:30:00',
read: true
}, {
id: 2,
from: 'Oliver Newton',
title: 'Look at this!',
received: '2015-06-15T08:00:00',
read: true
}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainController as ctrl">
<grouped-list model="ctrl.data" item-var="received" filter="ctrl.groupingReceived">
<h2>{{item.title}}<sub>{{item.from}}</sub></h2>
</grouped-list>
</div>

Ember.js - Bind array to radio button in the table/grid and when user selects the one in grid/table update the same array

following is my code: when i click any row in grid /table i should be
able to update the array elements back in the array
<script type="text/x-handlebars" data-template-name="application">
<table border="1">
{{#each content}}
<tr><td>{{name}} {{view Ember.RadioButton name="selectionTest" selectionBinding="isSelected" valueBinding="name"}}</td></tr>
{{/each}}
</table>
<div>Is Selected: {{isSelected}}</div>
</script>
console.clear();
window.App = Ember.Application.create({});
Ember.RadioButton = Ember.View.extend({
tagName: "input",
type: "radio",
arrBinding: 'App.ApplicationController.content',
attributeBindings: ["name", "type", "value", "checked:checked:"],
click: function () {
this.set("selection", this.$().val())
alert(this.$().val());
alert(arrBinding);
},
checked: function () {
return this.get("value") == this.get("selection");
}.property()
});
here i have declared the array elements
App.ApplicationController = Ember.ObjectController.extend({
isSelected: 'Ashish',
content:[
{
name: 'Ashish',
selected: false
},
{
name: 'Eben',
selected: false
},
{
name: 'Ronald',
selected: false
},
{
name: 'Jamie',
selected: false
}
]
});
here is the jsfiddle : http://jsfiddle.net/CM6fK/169/
Not totally sure what you're asking, but for a start you need to bind you selectionBinding to your controller:
<script type="text/x-handlebars" data-template-name="application">
<table border="1">
{{#each content}}
<tr><td>{{name}} {{view Ember.RadioButton name="selectionTest" selectionBinding=this.controller.isSelected valueBinding="name"}}</td></tr>
{{/each}}
</table>
<div>Is Selected: {{isSelected}}</div>
</script>
And as for the other bit. I think you need to change:
alert(arrBinding);
to
alert(this.arrBinding);
Though I'm really not sure what you're trying to achieve there.
Here is an updated jsfiddle: http://jsfiddle.net/CM6fK/172/

Create highcharts using angularjs ng-repeat

I have requested the json data containing all the information about people, and I want to a draw highcharts for each person based on the his information. I saw a solution here, but it seems that the config will always be overridden by the last li's config information. Is there a way to keep different configs for each highchart?
<div data-ng-repeat="a in people">
<h4>Method: {{ a.name }}</h4>
<highchart config="chartConfig"></highchart>
</div>
I encountered the same problem. It turns out that ng-repeat create new scope for each item, therefore the config attribute of highchart directive should correspond to the setting in ng-repeat. In your example, since you repeat the people by <div data-ng-repeat="a in people"> ,changing
<highchart config="chartConfig"></highchart>
to
<highchart config="a.chartConfig"></highchart>
should help.
I had create a plunker as an example.
You can use a partial view with a controller. Using ng-highcharts of course.
Like so, in your main you have:
<div data-ng-repeat="person in people">
<h4>Method: {{ person.name }}</h4>
<div data-ng-include="'/partial/chart.html'"></div>
</div>
Then in your partial, you have:
<div data-ng-controller="ChartController">
<highchart config="chartConfig"></highchart>
</div>
Then in your controller, you have:
app.controller('ChartController', function ($scope) {
$scope.chartConfig = {
chart: {
type: 'pie'
},
title: {
text: $scope.person.name
},
series: [{
data: $scope.person.chartdata
}]
};
});
Hope this helps.
You have to create a list then add to that list each chart configuration. Use ng-repeat in the list of charts:
//See: https://github.com/pablojim/highcharts-ng
var myapp = angular.module('myapp', ["highcharts-ng"]);
myapp.controller('myctrl', function ($scope) {
//The list who will contain each chart
$scope.chartlist = [];
//Chart 1
$scope.chartConfig = {
options: {
chart: {
type: 'bar'
}
},
series: [{
data: [10, 15]
}],
}
//Chart 2
$scope.chartConfig2 = {
options: {
chart: {
type: 'bar'
}
},
series: [{
data: [10, 15, 12, 8, 7]
}],
}
$scope.chartlist.push($scope.chartConfig);
$scope.chartlist.push($scope.chartConfig2);
});
then in your html use ng-repeat on the list of charts:
<div ng-app="myapp">
<div ng-controller="myctrl">
<div ng-repeat="char in chartlist" class="row">
<highchart id="chart1" config="char" class="span10"></highchart>
</div>
</div>
if you want to use dinamic data you can use a foreach to create each chart config, in this example I create a chart foreach object in the array 'a':
$scope.chartlist = [];
var a = [[1, 2],[2,4]];
function chardata(){
for (var i = 0; i < a.length; i++) {
$scope.chartConfig = {
options: {
chart: {
type: 'bar'
}
},
series: [{
data: a[i]
}],
}
$scope.chartlist.push($scope.chartConfig);
}
}
chardata();

Resources