filter by $key in ngRepeat - angularjs

I am trying to manipulate HTML5's audio element on an Angular backend.
(not a developer myself)
Using Angular-filter or any workaround to $key,
I would like to search by word.$key and not by the property 'value'.
var app = angular.module("app", ['angular.filter']);
app.controller("myCtrl", function($scope) {
$scope.words = {
'art': [{
'value': 'art',
'lang': 'english'
}],
'lamp': [{
'value': 'lamp',
'lang': 'english'
}, {
'value': 'lámpara',
'lang': 'espanol'
}],
'window': [{
'value': 'window',
'lang': 'english'
}, {
'value': 'ventana',
'lang': 'espanol'
}],
'bicycle': [{
'value': 'bicicleta',
'lang': 'espanol'
}]
};
$scope.play = function(id) {
document.getElementById(id).play()
};
});
app.filter('trustedAudioUrl', function($sce) {
return function(path, audioFile) {
return $sce.trustAsResourceUrl(path + audioFile);
};
});
app.directive('audios', function($sce) {
return {
restrict: 'AE',
scope: {
code: '=',
extra: '='
},
replace: true,
template: '<audio id="{{code}}-{{extra}}" ng-src="{{url}}"></audio>',
link: function(scope) {
scope.$watch('extra', function(newLang, oldLang) {
scope.$watch('code', function(newVal, oldVal) {
var prefix = 'http://www.almatsuy.com/Johanna/sound/words/';
if (newVal !== undefined) {
scope.url = $sce.trustAsResourceUrl(prefix + newLang + "/" + newVal + ".mp3");
}
})
});
}
};
});
td button {
text-transform: capitalize;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.4/angular-filter.js"></script>
<div ng-app="app" ng-controller="myCtrl">
<div ng-repeat="word in words">
<audios ng-repeat="audio in word" code="word.$key" extra="audio.lang" />
</div>
<input type="text" ng-model="searchKey" placeholder="search by key" />
<table>
<tbody ng-repeat="word in words | toArray: true">
<tr ng-repeat="t1 in word | fuzzyBy: 'value': searchKey">
<th>{{word.$key}} -- {{t1.lang}}</th>
<td>
<button ng-click="play(word.$key+'-'+t1.lang)">{{t1.value}}</button>
</td>
</tr>
</tbody>
</table>
</div>

I believe this might be something to do with old angular version.
I tried your code in JSFiddle, and in where i used Angular in version 1.1.1 it does not work, but as soon as i change version to 1.2.1 it works fine

Related

Angular recursive directive to represent tree structure needs adding file list

I have been attempting to update this directive to add fileList into the tree structure, but I was not successful. The original works fine (https://embed.plnkr.co/plunk/JgQu3r), but it considers directories only. In my data structure any directory can have a fileList, as well as any number of nested directoryList and so on.
function MainController($scope) {
$scope.menu = [{
name: 'one',
directoryList: [{
name: 'one'
}, {
name: 'two'
}],
fileList: ['one.pdf', 'two.pdf', 'three.pdf']
},
{
name: 'two',
directoryList: [{
name: 'one',
directoryList: [{
name: 'one'
}],
fileList: ['one.pdf', 'two.pdf', 'three.pdf', 'four.pdf']
}]
},
{
name: 'three'
}
];
}
function myMenu() {
return {
scope: {
myMenu: '=myMenu'
},
template: '<li ng-repeat="item in myMenu"><my-menu-item></my-menu-item></li>',
link: function(scope, elem) {}
}
}
function myMenuItem($compile) {
return {
template: '<a href ng-bind="item.name" ng-click="show($event)"></a>',
link: function(scope, element) {
if (angular.isArray(scope.item.menu)) {
element.append($compile('<ul ng-if="collapsed" my-menu="item.menu"></ul>')(scope));
}
scope.show = function($event) {
scope.collapsed = !scope.collapsed;
}
}
}
}
angular.module('app', [])
.controller('MainController', MainController)
.directive('myMenu', myMenu)
.directive('myMenuItem', myMenuItem);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.14/angular.js"></script>
<body ng-app="app" ng-controller="MainController">
<ul my-menu="menu">
</ul>
</body>
You need to distinguish between files and folders. Just treat the folders like you treat it in your example, and treat your files separately. The following snippet works, but I recommend that you take a minute to think about why and how it works.
function MainController($scope) {
$scope.menu = [{
name: 'one',
directoryList: [{
name: 'one'
}, {
name: 'two'
}],
fileList: ['one.pdf', 'two.pdf', 'three.pdf']
},
{
name: 'two',
directoryList: [{
name: 'one',
directoryList: [{
name: 'one'
}],
fileList: ['one.pdf', 'two.pdf', 'three.pdf', 'four.pdf']
}]
},
{
name: 'three'
}
];
}
function myMenu() {
return {
scope: {
myMenu: '=myMenu'
},
template: '<li ng-repeat="item in myMenu"><my-menu-item></my-menu-item></li>',
link: function(scope, elem) {}
}
}
function myMenuItem($compile) {
return {
template: `
<a href ng-bind="item.name" ng-click="show($event)"></a>
`,
link: function(scope, element) {
if (angular.isArray(scope.item.directoryList)) {
element.append($compile('<ul ng-if="!collapsed" my-menu="item.directoryList"></ul>')(scope));
}
if (angular.isArray(scope.item.fileList)) {
element.append($compile(`
<ul ng-if="item.fileList && !collapsed">
<li ng-repeat="file in item.fileList">{{file}}</li>
</ul>
`)(scope));
}
scope.collapsed = true;
scope.show = function($event) {
scope.collapsed = !scope.collapsed;
}
}
}
}
angular.module('app', [])
.controller('MainController', MainController)
.directive('myMenu', myMenu)
.directive('myMenuItem', myMenuItem);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.14/angular.js"></script>
<body ng-app="app" ng-controller="MainController">
<ul my-menu="menu">
</ul>
</body>

How to bind to a directive attribute?

I want the title for the highchart to be $scope.data.title but currently the attribute title interpret data.title as a string and a bind to the scope. I've tried putting "", {{}} around data.title the .html but it doesn't work. I think im missing something else.
index.html
<test-chart title="{{data.title}}">
<chart-series title="Series 1" type="line">
</chart-series>
<chart-series title="Series 3" type="column">
</chart-series>
</test-chart>
script.js
.directive('testChart', function() {
return {
restrict: 'E',
transclude: true,
controllerAs:'chartCtrl',
scope: {
},
controller: ['$scope', '$element', '$attrs', function ChartController($scope, $element, $attrs) {
$scope.data = {
title: 'HIGHGRAPH',
series: [{
title: 'series1',
type: 'line',
data: [1,2]
}, {
title: 'series2',
type: 'area',
data: [3,5]
}]
}
var hc = Highcharts.chart('highchart_container', {});
$scope.$watch("data",function(newValue,oldValue) {
hc.update({
title: {
text: newValue.title
}
})
})
this.addSeries = function(a) {
hc.addSeries({
name: a.title,
type: a.type,
data: [1,2,3,4,5,6]
})
};
}],
templateUrl: 'my-tabs.html'
};
EDIT: https://plnkr.co/edit/spUAkCjK61HgUGu40pZl?p=preview
This not works as intended, but is it possible to do it without the watch?
you won't have to put s.title inside ng-repeat. it should be outside.
Here is a working snippet.:-
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
});
app.directive('testChart', function() {
return {
restrict: 'E',
transclude: true,
controllerAs:'chartCtrl',
scope: {
},
controller: ['$scope', '$element', '$attrs', function ChartController($scope, $element, $attrs) {
$scope.data = {
title: 'HIGHGRAPH',
series: [{
title: 'series1',
type: 'line',
data: [1,2]
}, {
title: 'series2',
type: 'area',
data: [3,5]
}]
}
var hc = Highcharts.chart('highchart_container', {
title: {
text: $scope.data.title
}
});
this.addSeries = function(a) {
hc.addSeries({
name: a.title,
type: a.type,
data: [1,2,3,4,5,6]
})
};
}],
template: '<div> <p>This is a chart</p><ul> <li ng-repeat="s in series"> </li> </ul> <div id=\'highchart_container\'></div> <ng-transclude></ng-transclude> </div>'
};
})
.directive('chartSeries', function() {
return {
require: '^test-chart',
restrict: 'E',
transclude: true,
scope: {
title: '#'
},
link: function(scope, element, attrs, chartCtrl) {
chartCtrl.addSeries(attrs);
},
};
});
#highchart_container{
height:250px!important;
}
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<test-chart title="Custom title">
<chart-series title="Series 1" type="line">
</chart-series>
<chart-series title="Series 3" type="column">
</chart-series>
</test-chart>
</div>
Apparently this is how you must do it. Highchart docs for title
working plunker
Now my-tabs.html
<div>
<div id='highchart_container'></div>
<ng-transclude></ng-transclude>
</div>
and index.html
<body ng-app="docsTabsExample">
<test-chart>
<chart-series title="Series 1" type="line">
</chart-series>
<chart-series title="Series 3" type="column">
</chart-series>
</test-chart>
</body>
</html>
script.js
(function(angular) {
'use strict';
angular.module('docsTabsExample', [])
.directive('testChart', function() {
return {
restrict: 'E',
transclude: true,
controllerAs:'chartCtrl',
controller: ['$scope', '$element', '$attrs', function ChartController($scope, $element, $attrs) {
$scope.data = {
title: 'HIGHGRAPH',
series: [{
title: 'series1',
type: 'line',
data: [1,2]
}, {
title: 'series2',
type: 'area',
data: [3,5]
}]
}
var hc = Highcharts.chart('highchart_container', {
title: {
align:"center",
text:$scope.data.title
}
});
this.addSeries = function(a) {
hc.addSeries({
name: a.title,
type: a.type,
data: [1,2,3,4,5,6]
})
};
}],
templateUrl: 'my-tabs.html'
};
})
.directive('chartSeries', function() {
return {
require: '^test-chart',
restrict: 'E',
transclude: true,
scope: {
title: '#'
},
link: function(scope, element, attrs, chartCtrl) {
chartCtrl.addSeries(attrs);
},
};
});
})(window.angular);
i can't see why you need data binding if the title is a scope variable of the chartCtrl.
this will simply do the trick:
<div>
{{data.title}}
<div id='highchart_container'></div>
<ng-transclude></ng-transclude>
</div>
Plunker
Solved it by adding a watch on the object.
https://plnkr.co/edit/spUAkCjK61HgUGu40pZl?p=preview

Directive with template thet contains few quotation marks iside each other

I have an html component:
<div style="width:500px;">
<div ng-repeat="day in week" ng-class="{true:'possibleDayStyle', false:'notPossibleDay'}[day.selected]" ng-click="AddOrRemoveDay(day)">
{{day.name}}</div>
<button class="btnAddPossibleDays" ng-click="getAllSelectedDays()">Add</button>
</div>
I want to extract this code to a directive.
app.directive("weekDays", function(){
return{
restrict: "AEC",
replace: true,
template: '<div style="width:500px;">'+
'<div ng-repeat="day in week" ng-class="{true:"possibleDayStyle", false:"notPossibleDay"}[day.selected]" ng-click="AddOrRemoveDay(day)">'+
'{{day.name}}</div>'+
'<button class="btnAddPossibleDays" ng-click="getAllSelectedDays()">Add</button>'+
'</div>'
}
});
But I have a problem with ng-class that contains quotation marks inside quotation marks inside quotation marks
I dont want to extract it to another html page using templateurl.
how can i solve it?
This is full sample
angular.module("app", []);
angular.module("app").controller("ctrl", function($scope) {
$scope.selectedDays = [];
$scope.week = [{
name: 1,
selected: true
}, {
name: 2,
selected: false
}, {
name: 3,
selected: true
}, {
name: 4,
selected: false
}, {
name: 5,
selected: true
}, {
name: 6,
selected: false
}, {
name: 7,
selected: false
}];
$scope.getAllSelectedDays = function() {
$scope.selectedDays = [];
angular.forEach($scope.week, function(day) {
if (day.selected) {
$scope.selectedDays.push(day);
}
});
console.log($scope.selectedDays);
}
});
angular.module("app").directive("weekDays", function() {
return {
restrict: "AEC",
replace: true,
scope: {
array: "=",
action: "&"
},
template: "<div>" +
"<div ng-repeat=\"day in array\" ng-class=\"day.selected ? 'possibleDayStyle':'notPossibleDay'\">" +
"{{day.name}}" +
"<button ng-click=\"addOrRemoveDay(day)\">{{day.selected ? 'remove':'add'}}</button>" +
"</div> " +
"<button ng-click=\"getAllSelectedDays()\">get All selected days</button>" +
"</div>",
link: function(scope) {
scope.getAllSelectedDays = function() {
scope.action();
}
scope.addOrRemoveDay = function(day) {
day.selected ? day.selected = false : day.selected = true;
}
}
}
});
.possibleDayStyle {
background: blue;
}
.notPossibleDay {
background: red;
}
<!doctype html>
<html ng-app="app" ng-controller="ctrl">
<head>
</head>
<body>
<week-days array="week" action="getAllSelectedDays()"></week-days>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-rc.0/angular.js"></script>
</body>
</html>

Dynamically binding custom directive to ng-repeat

my controller has the json for my form then i have a directive that gets repeated to produce the form elements. based on the 'type' passed to the directive, the directive should know how to render the element.
but i don't know why it's not rendering the form templates properly here but that's a separate issue.
my immediate issue is, i can't seen to pass the ng-model and bind it correctly to the template.
does anyone see my problem?
var myApp = angular.module('myApp', []);
myApp.directive('ioProductElement', ['$compile', function ($compile) {
var dropdownTemplate = '<select ng-model="model" ng-options="option.Text for option in data"></select>';
var textAreaTemplate = '<textarea ng-model="model" class="form-control">{{ data }}</textarea>';
var radioListTemplate = '<span ng-repeat="item in data.Items"><input ng-model="model" type="radio" name="{{ data.Name }}" ng-checked="item.Selected" /><label>{{ item.ProductLabel }}</label> </span>';
return {
restrict: 'E',
replace: true,
scope: {
model: '=',
type: '=',
data: '='
},
link: function (scope, element) {
var getTemplate = function (type) {
var template = '';
switch (type) {
case 'SelectListItem':
template = dropdownTemplate;
scope.model = _.find(scope.data, {
Selected: true
});
break;
case 'TextArea':
template = textAreaTemplate;
break;
case 'RadioList':
template = radioListTemplate;
break;
}
return template;
};
element.html(getTemplate(scope.type));
$compile(element.contents())(scope);
}
};
}]);
myApp.controller('DynamicFormController', function () {
this.productElement = {};
this.product = {
ProductName: 'Online Form',
Company: 'TEST',
Data: []
};
this.productItems = [{
ProductLabel: "Status",
ProductType: "SelectListItem",
ProductData: [{
"Text": "Item1",
"Value": "1",
Selected: true
}, {
"Text": "Item2",
"Value": "2"
}]
}, {
ProductLabel: "Publication",
ProductType: "SelectListItem",
ProductData: [{
Text: 'Item1',
Value: '1'
}, {
Text: 'Item2',
Value: '2',
Selected: true
}]
}, {
ProductLabel: "Caption",
ProductType: "TextArea",
ProductData: "this is some data for the textarea"
}, {
ProductLabel: "Display Advertising",
ProductType: "RadioList",
ProductData: {
Name: "classifiedAdvertising",
Items: [{
Text: 'Full Page',
Selected: true
}, {
Text: '1/2 Page'
}]
}
}, {
ProductLabel: "Status2",
ProductType: "SelectListItem",
ProductData: [{
"Text": "Item1",
"Value": "1"
}, {
"Text": "Item2",
"Value": "2"
}, {
"Text": "Item3",
"Value": "3",
Selected: true
}]
}, ];
this.save = function () {
this.product.Data = this.productItems;
console.log('in save', this.product);
};
});
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.12/angular.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.4.0/lodash.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
<div class="col-sm-12" ng-app="myApp">
<br />
<form class="form-horizontal" ng-controller="DynamicFormController as ctrl">
<div class="form-group" ng-repeat="item in ctrl.productItems">
<label class="col-sm-2 control-label">{{ item.ProductLabel }}</label>
<div class="col-sm-10">
<io-product-element data-model="ctrl.productElement[item.ProductLabel]" data-type="item.ProductType" data-data="item.ProductData"></io-product-element>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input type="button" class="btn btn-info" data-ng-click="ctrl.save()" value="Submit" />
product: {{ ctrl.product | json }}
</div>
</div>
</form>
</div>
Try To add a break statement in the first switch case
//[...]
switch (type) {
case 'SelectListItem':
template = dropdownTemplate;
scope.model = _.find(scope.data, {
Selected: true
});
break;
case 'TextArea':
template = textAreaTemplate;
break;
case 'RadioList':
template = radioListTemplate;
break;
}
//[...]

ng-repeat do not evaluate from $sce.trustAsHtml inside directive

I have a directive that has a piece of custom HTML that I can pass in as a custom option. I would like to use ng-repeat inside the custom HTML, but it is not being displayed. Here is the code.
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.local = {
options: {
columns: [{
name: 'product_id',
label: 'Product ID'
}, {
name: 'product_name',
label: 'Name'
}],
getBody: function( col, i ) {
return col.name == 'product_id' ? col.label : '<div class="dropdown product-status"><button class="btn btn-primary dropdown-toggle" data-toggle="dropdown">Status<span class="caret"></span></button><span class="dropdown-arrow"></span><ul class="dropdown-menu"><li ng-repeat="one_status in dataset.status"><a class="status all" ng-click="dataset.updateStatus(one_status.status_id)" ng-bind="one_status.status_name"></a></li></ul></div>';
}
},
dataset: {
status: [{
status_id: 1,
status_name: 'first draft'
}, {
status_id: 2,
status_name: 'in edit'
}]
}
};
});
app.directive('test', function($sce) {
var linkFunc = function(scope) {
scope.getBody = function( col, index ) {
return $sce.trustAsHtml( scope.options.getBody( col, index ) );
};
};
return {
link: linkFunc,
scope: {
options: '=',
dataset: '='
},
templateUrl: 'test.html'
};
});
http://plnkr.co/edit/mCynQWtQElTGfoLXZHqZ?p=preview
you need to make sure $sce is in a part of your controller
check this out
-- http://jsfiddle.net/3J25M/2/
.controller('ngBindHtmlCtrl', ['$scope','$sce', function ngBindHtmlCtrl($scope, $sce)
...etc
also, check this question out: AngularJS using $sce.trustAsHtml with ng-repeat

Resources