I have got this code below and I want to know how I can add a clickable link to the boxes under each title.
I want this Call on Skype to appear in the first box. But I cannot get it to work as the whole function just stops working when I add it.
function MyCtrl($scope) {
$scope.environment_service_packages =
[
{name: 'obj1', info: {text: '<?php echo "A html link below \\n\\n Call on Skype"; ?>', show: true}},
{name: 'obj2', info: {text: 'some extra info for obj2', show: true}},
{name: 'obj3', info: {text: 'some extra info for obj3', show: true}},
{name: 'obj4', info: {text: 'some extra info for obj4', show: false}},
];
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app>
<table ng-controller="MyCtrl" class="table table-hover table-striped">
<tr class="info">
<td>...</td>
</tr>
<tbody ng-repeat="x in environment_service_packages">
<tr ng-click="x.info.show = !x.info.show">
<td> {{ x.name }}
</tr>
<tr ng-show="x.info.show">
<td>
<pre>{{ x.info.text }}</pre>
</td>
</tr>
</tbody>
</table>
</body>
Putting ng-repeat on the tbody will create a body for every member in the array.
Try putting ng-repeat-start on the first row and ng-repeat-end on the second row.
You can't run PHP code in client side...
you need to change HTML to something like:
Call on Skype
Related
Working with Knockout templates, all of the examples seem to pass in single values to the template instead of array data. I have a template which will create some basic HTML, and then render a table using the data passed in to the template. Here is how it looks:
<script type="text/html" id="my-template">
<p>Here is the data</p>
[MORE HTML DATA HERE]
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Surname</th>
</tr>
</thead>
<tbody data-bind="foreach: [WHAT DO I PUT HERE???]">
<tr>
<td data-bind="text: Id"></td>
<td data-bind="text: FirstName"></td>
<td data-bind="text: Surname"></td>
</tr>
</tbody>
</table>
</script>
<div data-bind="template: { name: 'my-template', data: PersonArray1 }"></div>
<div data-bind="template: { name: 'my-template', data: PersonArray2 }"></div>
<div data-bind="template: { name: 'my-template', data: PersonArray3 }"></div>
The templates do support a foreach binding, but I don't think I can use that as I don't want the template HTML heading data marked [MORE HTML DATA HERE] repeated for every item in the array.
I want the foreach binding within the template as in my rough example above. Is there a way I can make this work? I think the answer is in the placeholder i have marked with [WHAT DO I PUT HERE???] above, but I don't know if there is a variable which holds top-level template data.
What you are looking for is the $data parameter which will give you each entry from the supplied array:
var myViewModel = {
PersonArray1 : [
{ Id: 1, FirstName: "Alice", Surname: "Bloggs" },
{ Id: 2, FirstName: "Bob", Surname: "Bloggs" },
{ Id: 3, FirstName: "Claire", Surname: "Bloggs" }
]
};
ko.applyBindings(myViewModel)
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script type="text/html" id="my-template">
<p>Here is the data</p>
[MORE HTML DATA HERE]
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Surname</th>
</tr>
</thead>
<tbody data-bind="foreach: $data">
<tr>
<td data-bind="text: Id"></td>
<td data-bind="text: FirstName"></td>
<td data-bind="text: Surname"></td>
</tr>
</tbody>
</table>
</script>
<div data-bind="template: { name: 'my-template', data: PersonArray1 }"></div>
I found the answer from this link, and the solution was posted by the creator himself.
https://github.com/knockout/knockout/issues/246
The solution is supplied in this fiddle:
http://jsfiddle.net/b9WWF/
The part of interest is where you call your template, instead of supplying an object directly to the data attribute, you can supply data in named values as follows:
<div data-bind="template: { name: 'my-template', data: { people: PersonArray1 } }"></div>
<div data-bind="template: { name: 'my-template', data: { people: PersonArray2, displayAdmins: false } }"></div>
You then access the array in your template as follows (I'm using my code above as an example):
<tbody data-bind="foreach: people">
Please find the attached fiddle where I want to post a warning mesaage "No data to display" if the filter fais to match any results in the button clicks.
Fiddle ng-repeat filter
I have given condition for both table and message so that they should be displayed as and when the clicks happen.
<div ng-show="name===null">No results</div>
The above message should be displayed if there are no satisfying data in the table based on link clicks,together the table should be hidden.
I tried to give conditions based on property name but its not working.
Check your fiddle http://jsfiddle.net/w0L4o8jm/6/
By default I am making filter with Fruit. You can change it in the controller.
Coming to the answer, Calculate the filtered items length according to the filter. If length 0 or name '', then show no results. Otherwise show results in the table. Just copy paste the below code in your fiddle and check it out.
<html ng-app="app">
<a ng-click="name = 'Fruit'">Fruit</a>
<a ng-click="name = 'Nut'">Nut</a>
<a ng-click="name = 'Seed'">Seed</a>
<body ng-controller="main">
<a ng-click="name = ''">clear filter</a>
<br> <br> <br>
<div ng-show="(name=='' || !filtered.length)">No results</div>
<div ng-repeat="link in filtered = (links|filter:name)"></div>
<table class="table" ng-show="(filtered.length != 0 && name!='')">
<thead>
<tr>
<th>Target</th>
<th>Level</th>
<tr>
<tbody>
<tr ng-repeat="link in links|filter:name">
<td>
{{link.name}}
</td>
<td>
{{link.category}}
</td>
</tr>
</tbody>
</table>
</body>
Controller code
var app = angular.module('app', []);
app.controller('main', function($scope) {
$scope.filters = { };
$scope.name='Fruit';
$scope.links = [
{name: 'Apple', category: 'Fruit'},
{name: 'Pear', category: 'Fruit'},
{name: 'Almond', category: 'Nut'},
{name: 'Mango', category: 'Fruit'},
{name: 'Cashew', category: 'Nut'}
];
});
For Angular prior to 1.3
Assign the results to a new variable (e.g. filtered) and access it:
<div ng-repeat="link in filtered = (links|filter:name)"></div>
For Angular 1.3+
Use an alias expression (Docs: Angular 1.3.0: ngRepeat, scroll down to the Arguments section):
<div ng-repeat="link in links|filter:name as filtered"></div>
Try to use this code
Demo
<body ng-app="app" ng-controller="main">
<a ng-click="name = 'Fruit'">Fruit</a>
<a ng-click="name = 'Nut'">Nut</a>
<a ng-click="name = 'Seed'">Seed</a>
<a ng-click="name = ''">clear filter</a>
<br> <br> <br>
<div ng-show="name ==''">No results</div>
<table class="table" ng-show="name!=''">
<thead>
<tr>
<th>Target</th>
<th>Level</th>
<tr>
<tbody>
<tr ng-repeat="link in links | filter:name">
<td>
{{link.name}}
</td>
<td>
{{link.category}}
</td>
</tr>
</tbody>
</table>
var app = angular.module('app', []);
app.controller('main', function($scope) {
$scope.filters = { };
$scope.name = '';
$scope.links = [
{name: 'Apple', category: 'Fruit'},
{name: 'Pear', category: 'Fruit'},
{name: 'Almond', category: 'Nut'},
{name: 'Mango', category: 'Fruit'},
{name: 'Cashew', category: 'Nut'}
];
});
Here you go! Updated fiddle
You had a few issues in there:
your ng-controller was on a div but you were setting name outside controller
<div ng-show="name===null">No results</div> Here you were comparing name with null but you were setting it to empty string in clear filter
Hope it helps!
Edit: On clear filter it was not showing all the items. Fixed and updated fiddle
When I run this code on my PHP website, it works but when adding a \n after 'text:' as php to make a new line, the entries in the table below the blue title at the top stop showing. Below is a snippet of what the code is but it does not run php so it doesn't show the error.
function MyCtrl($scope) {
$scope.environment_service_packages =
[
{name: 'obj1', info: {text: '<?php echo "This: \n breaks the code"; ?>', show: true}},
{name: 'obj2', info: {text: 'some extra info for obj2', show: false}},
];
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app>
<table ng-controller="MyCtrl" class="table table-hover table-striped">
<tr class="info">
<td>...</td>
</tr>
<tbody ng-repeat="x in environment_service_packages">
<tr ng-click="x.info.show = !x.info.show">
<td> {{ x.name }}
</tr>
<tr ng-show="x.info.show">
<td>
{{ x.info.text }}
</td>
</tr>
</tbody>
</table>
</body>
You actually need to escape the line-break twice.
One escape for JavaScript and one for php
Your current string generates this php:
<?php echo "This:
breaks the code"; ?>
because the \n is evaluated by javascript into a linefeed character and this makes the php invalid.
You should use this string instead:
'<?php echo "This: \\n does not break the code"; ?>'
\n will not show in HTML. You have to coding like this.
function MyCtrl($scope) {
$scope.environment_service_packages =
[
// <br> will be convert to <br>
{name: 'obj1', info: {text: '<?php echo "This: <br> breaks the code"; ?>', show: true}},
{name: 'obj2', info: {text: 'some extra info for obj2', show: false}},
];
}
I am new to Angular, and I would like to do some non-trivial input validation.
Basically I have a table. Each row contains three text inputs. When the user types into any text inputs, I would like to check whether the table contains at least one row with three non-blank input fields. If it does, I want to show a message.
I have no idea how to do this cleanly in Angular, any help would be much appreciated.
This is my HTML:
<tr data-ng-repeat="i in [1,2,3,4,5]">
<td data-ng-repeat="i in [1,2,3]">
<input ng-model="choice.selected" ng-change='checkAnswer(choice)' type="text" />
</td>
</tr>
...
<div ng-show="haveCompleteRow">we have a complete row!</div>
And controller:
$scope.haveCompleteRow = false;
$scope.checkAnswer=function(choice){
$scope.haveCompleteRow = true; // what to do here?
}
Here is a plunker demonstrating the issue: http://plnkr.co/edit/Ws3DxRPFuuJskt8EUqBB
To be honest, I wouldn't call this form validation. But for starters, it would be a lot simpler if you had a real model to observer, instead of an array in the template. The way you started will, or at least could, lead you to dom-manipulation inside the controller, which is a no-go for angular.
A simple first sketch with a model could be:
app.controller('TestCtrl', ['$scope', function ($scope) {
$scope.rows = [
[{text: ''}, {text: ''}, {text: ''}],
[{text: ''}, {text: ''}, {text: ''}],
[{text: ''}, {text: ''}, {text: ''}]
];
$scope.haveCompleteRow = false;
// watch for changes in `rows` (deep, see last parameter `true`).
$scope.$watch('rows', function (rows) {
// and update `haveCompleteRow` accordingly
$scope.haveCompleteRow = rows.some(function (col) {
return col.every(function (cell) {
return cell.text.length > 0;
});
});
}, true);
}]);
with:
<body ng-controller="TestCtrl">
<table>
<thead>
<tr>
<th>Col1</th>
<th>Col2</th>
<th>Col3</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="row in rows">
<td data-ng-repeat="cell in row">
<input ng-model="cell.text" type="text" />
</td>
</tr>
</tbody>
</table>
<div ng-show="haveCompleteRow">we have a complete row!</div>
</body>
as the template.
Demo: http://jsbin.com/URaconiX/2/
I want to get a table with these columns:
[Name]
[Club]
[Dynamic1]
[Dynamic2]
[Dynamic3]
etc etc.
I tried this:
<table>
<tbody data-bind="template: { name: 'rowTmpl', foreach: runners }">
</tbody>
</table>
<script id="rowTmpl" type="text/html">
<tr data-bind="template: { name: 'colTmpl', foreach: radios }" >
<td data-bind="text: name"></td>
<td data-bind="text: club"></td>
</tr>
</script>
<script id="colTmpl" type="text/html">
<td>aa</td>
</script>
#section Scripts{
<script src="/Scripts/knockout-1.3.0beta.js" type="text/javascript"></script>
<script type="text/javascript">
var vm = {
id: 1,
name: 'H21',
radios: ['2km', '4km', 'mål'],
runners: ko.observableArray([
{ name: 'Mikael Eliasson', club: 'Göteborg-Majorna OK', radios: ko.observableArray([{}, {}, {}]) },
{ name: 'Ola Martner', club: 'Göteborg-Majorna OK', radios: ko.observableArray([{}, {}, {}]) }
])
};
ko.applyBindings(vm);
</script>
}
My problem is that the tds inside colTmpl is not databoud, it's empty and placed after the third column with the text 'aa'. See this fiddle.
If you are using 1.3 beta (your fiddle is referencing the latest build), then you can do this:
<table>
<tbody data-bind="foreach: runners">
<tr>
<td data-bind="text: name"></td>
<td data-bind="text: club"></td>
<!-- ko foreach: radios-->
<td>aa</td>
<!-- /ko -->
</tr>
</tbody>
</table>
Sample here: http://jsfiddle.net/rniemeyer/bd7DT/
If you need to do this prior to 1.3 with jQuery templates, then you would want to pass the first item in your array into the template via templateOptions and do an {{if}} to check if you are on the first radio and render the two cells. Another option in jQuery templates is to use {{each}} around your dynamic cells rather than the foreach option of the template binding on the parent. You would lose some efficiency, if your columns are frequently changing dynamically. I can provide a sample for these two options, if necessary.
It is because of the fact that the content of <tr data-bind="template: { name: 'colTmpl', foreach: radios }" > is getting replaced by the template you specify.
If you instead do:
<script id="rowTmpl" type="text/html">
<tr>
<td data-bind="text: name"></td>
<td data-bind="text: club"></td>
<td data-bind="template: { name: 'colTmpl', foreach: radios }" ></td>
</tr>
</script>
<script id="colTmpl" type="text/html">
<span> . aa . </span>
</script>
It will render.