Typo3 Fluid Loop Through Properties - loops

I have a working Fluid template file that looks like this:
<table class="my-extension" >
<tr>
<td>
<f:translate key="my-extension_domain_model_appointment.translator" />
</td>
<td>
{appointment.translator}
</td>
</tr>
<tr>
<td>
<f:translate key="my-extension_model_appointment.bringtranslator" />
</td>
<td>
{appointment.bringtranslator}
</td>
</tr>
</table>
In my model I got the class appointment with the two properties translator and bringtranslator.
I want to iterate through all properties so in case I add another one I don't need to change anything in my html file.
So I'm searching for something like this:
<f:for each="{appointmentproperty}" as="property">
<tr>
<td>
<f:translate key="my-extension_domain_model_appointment."+property />
</td>
<td>
{appointment.property}
</td>
</tr>
</f:for>
Can someone tell me how to do this with fluid? (btw. I'm still using the old 4.7.7 Version)

You cannot do this out of the box. However if you access a property of your model in fluid ({model.property}), under the hood the getProperty() method is called.
So if you want some magic functionality that automatically expands your view if you model grows, you have to implement it.
I'll give you one example, but there are other ways to do this: You could add a method to your model:
/**
* #return array
*/
public function getPropertiesForTableView() {
return array(
'property1' => $this->getProperty1(),
'property2' => $this->getProperty2()
);
}
In your view, you can now access this new Getter Method:
<f:for each="{appointment.propertiesForTableView}" as="propertyValue" key='propertyName'>
<tr>
<td>
<f:translate key="my-extension_domain_model_appointment.{propertyName}" />
</td>
<td>
{propertyValue}
</td>
</tr>
</f:for>
You still have to "do" something if you add a property that should show in your view (adding the property to your array). But you dont need to adjust your template.

<f:for each="{appointments}" as="appointment">
<tr>
<td>
<f:translate key="my-extension_domain_model_appointment."{appointment.translator.uid} />
</td>
<td>
{appointment.bringtranslator}
</td>
</tr>
</f:for>
If your appointment object also has other objects, you can iterate them again in your iteration:
<f:for each="{appointments}" as="appointment">
{appointment.title}
<f:for each="{appointment.translators}" as="translator">
{translator.name}
</f:for>
</f:for>

I think you search for something like this:
Typo3 Extbase Guide
Here you can see, that you can give an array to the alias and then you can cycle through. Maybe you can come to the answer by this? Please comment, if you found the correct way.
<f:alias map="{employees: {0: {first_name: 'Stefan', city: 'Lindlar'},1: {first_name: 'Petra', city: 'Lindlar'},2: {first_name: 'Sascha', city: 'Remscheid'},3: {first_name: 'Patrick', city: 'Bonn'},4: {first_name: 'Sven', city: 'Gummersbach'},5: {first_name: 'Andrea', city: 'Wuppertal'}}}">
<table cellpadding="5" cellspacing="0" border="2">
<f:groupedFor each="{employees}" as="employeesByCity" groupBy="city" groupKey="city">
<tr>
<th colspan="2">{city}</th>
</tr>
<f:for each="{employeesByCity}" as="employee">
<tr>
<td>{employee.first_name}</td>
<td>{employee.city}</td>
</tr>
</f:for>
</f:groupedFor>
</table>
</f:alias>

Related

Does react have a markup binding syntax?

I'm learning React and this is the way my tutorial says to bind, say, a table to a javascript array of Article objects:
<table>
<tbody>
{
articles.map(a =>
{
return <tr>
<td>
{a.property1}
</td>
<td>
{a.property2}
</td>
</tr>
})
}
</tbody>
</table>
I had been using knockout js, which supports a syntax that seems much more natural for this, in that it doesn't have all the curly braces and parentheses, which makes it much easier to see the structure of the HTML that you're trying to produce:
<table>
<tbody>
<tr data-bind="foreach: a in articles">
<td>
{a.property1}
</td>
<td>
{a.property2}
</td>
</tr>
</tbody>
</table>
Does React have a similar declarative style syntax?
JSX is just syntax sugar for JavaScript. This:
<tbody>
{
articles.map(a =>
{
return <tr> ...
gets transpiled to:
React.createElement('tbody', null,
articles.map(a => {
return React.createElement('tr', null,
// <td> elements
)
})
)
The brackets {} are needed in the JSX when interpolating a JavaScript expression into JSX, to indicate that what followed should be parsed as JavaScript rather than as JSX's HTML-like markup - that is, there's no way around the { in
<tbody>
{
articles.map(
in order to interpolate the articles into the <tbody>.
The best you'll be able to do is remove the { and return and use the arrow function's concise return in the .map callback:
<table>
<tbody>
{
articles.map(a => <tr>
<td>
{a.property1}
</td>
<td>
{a.property2}
</td>
</tr>
)
}
</tbody>
</table>
One of the arguable main benefits of React (for new learners who already know JS) is that it's just JavaScript, other than a few additional syntax rules about JSX. So there's no special syntax like foreach: a in articles - instead, the ordinary JavaScript logic for looping over an array is used, articles.map(a =>.

ng-click in ng-repeat with url redirect

I am trying to redirect the page using ng-click which is avail in ng-repeat.
ng-repeat code:
<tr ng-repeat="students in studlist" ng-click="gotoProfile(1)">
<td width="12%" class="student-list-pic-column"><img src="<?=base_url()."data/student-img/{{ students.photo }}";?>"></td>
<td width="50%" class="custom-table-border-body text-left">{{ students.studname }}</td>
<td width="38%">{{ students.bid }}</td>
</tr>
<tr ng-show="!studlist.length">
<td colspan="3" class="custom-table-border-body text-center">
Search student name ...
</td>
</tr>
Here in ng-click="gotoProfile(1)" instead of that 1 I need {{students.id}} but unable to get
Controller function:
$scope.gotoProfile = function (sid) {
console.log($scope.purl);
var rurl = $scope.purl+sid;
$location.url(rurl);
};
When I run this I am getting url
http://localhost/product/tcm_dev/utility/dashboard#/http://localhost/product/tcm_dev/utility/student/profile/1
like this.
Please help.
Thank You
Prashant
use <tr ng-repeat="students in studlist" ng-click="gotoProfile(student.id)"> to send student.id
and how about use $window.location.href=(rurl); instead of $location.url(rurl);
if you want to open a new page, use $window.location.href=(rurl,'_blank');

angular smart-table plugin/directive wont work

I am trying to use smart-tables, Select row plugin, I have added 'smart-table' to my application, like so var myApp = angular.module('myApp', ['ui.bootstrap','smart-table']);
I have also changed the first line of the directive (since it didn't work to just copy-paste it), I changed this:
ng.module('smart-table').directive('stSelectRow', ['stConfig', function (stConfig)
To this: myApp.directive('stSelectRow', ['stConfig', function (stConfig) {
In my html I have this
<table st-table="displayedCollection" st-safe-src="safeCollection" class="table">
<thead>
<tr>
<th>Title</th>
<th>FieldOne</th>
<th>FieldTwo</th>
<th>FieldThree</th>
</tr>
</thead>
<tbody>
<tr st-select-row="row" st-select-mode="multiple" ng-repeat="row in displayedCollection">
<td> {{row.Title}} </td>
<td> {{row.FieldOne}} </td>
<td> {{row.FieldTwo}} </td>
<td> {{row.FieldThree}} </td>
</tr>
</tbody>
If I remove the st-select-row="row" st-select-mode="multiple" the table works, but obviously not the row selection
I am guessing I'm missing some dependency or something, I have only added smart-table.min.js to my application, but I think that should be enough, the directive (select row plugin) is added inside my app.js file. What could it be?
It is because the documentation on the site isn't exactly clear. But it does say
...and the class attribute st-selected is set on the tr element.
You have to define the CSS for st-selected for it to "work":
.st-selected{
background: #216eff !important;
color: white !important;
}

ng-init miscalculates aliased index after array.splice

I have encountered a strange behavior related to ng-init, any help would be appreciated.
I have a model object which has a flats property that is an array of flat objects. Each flat object has rooms property which is an array of room objects.
I'm trying to display flat and rooms as follows;
<table ng-repeat="flat in model.flats" ng-init="flatIndex = $index">
<thead>
<tr>
<td>{{flatIndex+1}}. {{flat.name}}</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="room in flat.rooms" ng-init="roomIndex = $index">
<td>{{roomIndex+1}}. {{room.name}}</td>
</tr>
</tbody>
</table>
If i delete a flat or room by using array.splice flatIndex and roomIndex variables doesn't seem to update properly even though $index and ui updates properly.
You can see the problem here in action.
Try to delete 1st, 2nd or 3rd flat or room object by clicking the delete link. Deleting last object from the array doesn't really expose the problem.
Any workarounds would also be appreciated.
This is a known behavior when you use ng-init, the scope property values set by ng-init are not watched and they don't update when you remove items from array to reflect the refreshed index position. So don't use ng-init, instead just use $index (deleteFlat($index)) and flat object reference (to get hold of rooms deleteRoom(flat,$index)).
<table ng-repeat="flat in model.flats track by flat.id">
<thead>
<tr>
<td colspan="2">{{$index+1}}. {{flat.name}}</td>
<td>DELETE FLAT</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="room in flat.rooms track by room.id">
<td> </td>
<td>{{$index+1}}. {{room.name}}</td>
<td>DELETE ROOM</td>
</tr>
</tbody>
</table>
and
$scope.deleteFlat = function(flatIndex){
$scope.model.flats.splice(flatIndex,1);
};
$scope.deleteRoom = function(flat,roomIndex){
flat.rooms.splice(roomIndex,1);
};
Plnkr
Or better off use the ids itself, deleteFlat(flat.id) and deleteRoom(room.id, flat).
<table ng-repeat="flat in model.flats track by flat.id">
<thead>
<tr>
<td colspan="2">{{$index + 1}}. {{flat.name}}</td>
<td>DELETE FLAT</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="room in flat.rooms track by room.id">
<td> </td>
<td>{{$index+1}}. {{room.name}}</td>
<td>DELETE ROOM</td>
</tr>
</tbody>
</table>
and
$scope.deleteFlat = function(flatId){
$scope.model.flats.splice(_getItemIndex(flatId, $scope.model.flats), 1);
};
$scope.deleteRoom = function(roomId, flat){
flat.rooms.splice(_getItemIndex(roomId, flat.rooms), 1);
};
function _getItemIndex(imtId, itms){
var id ;
itms.some(function(itm, idx){
return (itm.id === imtId) && (id = idx)
});
return id;
}
Plnkr2

ICEfaces: How to pass parameters from one page to another

I have this simple scenario which doesn't work: I use icefaces and i have a simple page with some inputTexts and a submit button, this button will redirect to another page that will display the values of these inputTexts... my question is how can i get the values of these inputTexts from the request and display them in another page?
When i use the following API in the other page backbean, i get only the name of the page that holds the inputTexts:
FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
I really did spent alot of time trying to get this thing to work, so any help will be appreciated.. THx
my page code is:
<ice:form id="form1">
<table border="0">
<tbody>
<tr>
<td><ice:outputText value="Name"></ice:outputText><br></br></td>
<td><ice:inputText id="name" value="#{newContest.name}"></ice:inputText></td>
</tr>
<tr>
<td><ice:outputText value="End Date"></ice:outputText></td>
<td><ice:inputText id="endDate" value="#{newContest.endDate}"></ice:inputText></td>
</tr>
<tr>
<td><ice:outputText value="private? (only you can see the entries)"></ice:outputText></td>
<td><ice:inputText id="private" value="#{newContest.isPublic}"></ice:inputText></td>
</tr>
<tr>
<td><ice:outputText value="Price"></ice:outputText></td>
<td><ice:inputText id="price" value="#{newContest.price}"></ice:inputText></td>
</tr>
<tr>
<td><ice:outputText value="Description"></ice:outputText></td>
<td><ice:inputTextarea id="description" value="#{newContest.description}"></ice:inputTextarea></td>
</tr>
<tr>
<td><br></br><ice:commandButton value="proceed to payment" style="color:blue" action="#{newContest.createContest}"></ice:commandButton></td>
</tr>
</tbody>
</table>
You can bind another bean with current one as a managed property in faces-config.xml as follows.
<managed-bean>
<managed-bean-name>newContest</managed-bean-name>
<managed-bean-class>com.newContest</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>anotherBackingBean</property-name>
<property-class>com.AnotherBackingBean</property-class>
<value>#{anotherBackingBean}</value>
</managed-property>
</managed-bean>
<navigation-rule>
<navigation-case>
<from-outcome>view-anotherBackingBean</from-outcome>
<to-view-id>/jsp/another-page.jspx</to-view-id>
</navigation-case>
</navigation-rule>
Bean Content
Class NewContest {
public AnotherBackingBean anotherBackingBean;
//-- set/get & other methods
public String redirectToAnotherBackingBean(){
anotherBackingBean.setSomeObject(object);
//-- set custom fields
return "view-anotherBackingBean";
}
}
Then you can get your fields directly available in other bean which have been set in current bean.

Resources