I am building my first AngularJS app comming from backbone. I have a list where the user can select an item. The goal is show the details of the selected item in a view below the list. The list-view and detail-view are both part of the main-view.
my list view
<div id="rfc-records" class="container-fluid">
<div ng-repeat="record in records" ng-click="selectRow()" class="row select table-row">
<div class="col-lg-1 center">
{{record.id}}
</div>
<div class="col-lg-1 center">
{{record.rfcObject}}
</div>
<div class="col-lg-5">
{{record.rfcFunction}}
</div>
<div class="col-lg-2">
{{record.status}}
</div>
<div class="col-lg-3">
{{mii.utils.date.extToIntDate(record.firstProcessing)}}
</div>
</div>
</div>
As you see I already added an event to each row: ng-click="selectRow()".
It is unclear to me how to know the selected row in this function. I could do something like this :
ng-click="selectRow(record)
MainController
$scope.selectRow = function(record){
alert(record.id); // undefined
}
The result is undefined so this does not work. Plus this seems like a bad approach to pass the model back from the view to the controller. I might be able to get the application working but I have the feeling that I won't be using the paradigm as intended.
In backbone I would have a seperate view for each row where the model is bound to. But in Angular models aren't as explicit as in backbone.
In general I don't really understand how models work in Angular. R
Regarding this example I have the following questions:
How do I know what item is selected in the list
Where should I put the selectRow function? In the controller of the Mainview or in the list-view directive?
How do I pass the selected model to the details-view.
Well, passing current item into ngClick handler is pretty usual way to solve this task. I'm not sure why it's not working for you, it should. Here is the example of this typical approach.
In backbone I would have a seperate view for each row where the model is bound to. But in Angular models aren't as explicit as in backbone.
Actually Angular is even more elegant in this concern. You still have model available in every iterated row. You can refer current child scope as this in controller. So in your case if you don't want to pass record object into controller function on click, you can use this and it will point to the current scope object (remember that ngRepeat creates new child scope for every row):
$scope.selectRow = function() {
alert(this.record.id);
};
and you don't have to pass anything in HTML:
ng-click="selectRow()"
Demo: http://plnkr.co/edit/kN0vB6N6v7XnqASRSmAd?p=preview
ng-click and ng-repeat are in same div. You can add a new div in this repeated div like and this is works for me :
<div id="rfc-records" class="container-fluid">
<div ng-repeat="record in records" class="row select table-row">
<div class="col-lg-1 center">
Select This item<input type=button ng-click="selectRow(record)">
</div>
<div class="col-lg-1 center">
{{record.id}}
</div>
<div class="col-lg-1 center">
{{record.rfcObject}}
</div>
<div class="col-lg-5">
{{record.rfcFunction}}
</div>
<div class="col-lg-2">
{{record.status}}
</div>
<div class="col-lg-3">
{{mii.utils.date.extToIntDate(record.firstProcessing)}}
</div>
</div>
</div>
Related
I use Angular 8 and I have 3 components:
CalculationFirst : app-calculation-first
CalculationSecond : app-calculation-second
CalculationThird : app-calculation-third
CalculationFirst is the "parent" component and has CalculationSecond as a "child" in a way that I use CalculationSecond inside html template of CalculationFirst.
So in CalculationFirst.component.html it looks like this:
<div class="container">
<form #f="ngForm" (ngSubmit)="submit()" novalidate *ngIf="settings.isloaded == true">
<div class="row">
<app-calculation-second [elements]="settings.seconds.elements" [epics]="epics"[types]="types" (opendialoglistevent)="openDialogList($event)"></app-calculation-second>
</div>
</form>
</div>
Then CalculationSecond.component.html looks like this:
<div class="col-lg-2 box">
<div class="row">
<div class="row content" *ngFor="let element of elements;">
<div class="col-lg-14">
<app-calculation-third [elem]="element" [types]="types"></app-calculation-third>
</div>
</div>
</div>
</div>
And finally CalculationThird.component.html looks like :
<div class="col-lg-14">
TEST_TEXT_1
{{elem}}
TEST_TEXT_2
</div>
Now, the problem is if I were to just look at my rendered page, only TEST_TEXT_1 page shows, {{elem}} does not render and neither does TEST_TEXT_2. If I am to check the value of elem, it is undefined. I would expect to get an error that I am trying to display undefined, however I do not get anything. My environment.ts is not set to production, so I do not know if my error is not big enough for angular to inform me. (On a tangent, I don't even get an error if I use a json object in an *ngFor instead of an enumerable (Array), but I'm still not sure if I have some lacking setting).
I have also tried, when I use the third component, to not pass the element from *ngFor but to pass a handmade object {'elemId':0}, this had the same result.
If I move :
<app-calculation-third [elem]="element" [types]="types"></app-calculation-third>
to CalculationFirst, making it a direct child, it works perfectly fine, regardless of what I put in there. Is there a limit to the amount of child components you can have? Am I missing something?
*Edit: Also for those who suggested it is the *ngFor or the usage of different variables, I can make CalculationSecond look like the following and still it doesn't work:
<div class="col-lg-2 box">
<div class="row">
<div class="row content" *ngFor="let element of elements;">
<div class="col-lg-14">
</div>
</div>
</div>
<app-calculation-third [elem]="{ elementId: '' }" [types]="types"></app-calculation-third>
</div>
You are passing the elements to seconds input.
[seconds]="settings.seconds.elements"
But you use elements in your app-second-calculation element.
Lets say I have 2 divs side by side. (for the sake of argument using bootstrap lets say they are both 6 columns each)
If I drag an object into the column on the right, and then click a button below that column, I want the column on the left to mirror the one on the right. (so they are now identical)
I know we can do this with 2 way binding in real time, but I am wondering if it is possible to invoke 2 way binding on a click event? I also looked into angular copy, but there is very little documentation on this that i understand.
<div class="col-sm-12">
<div class="col-sm-6">
<div class="col-sm-12 left_column">
<p>{{master}}</p>
</div>
</div>
<div class="col-sm-6">
<div class="col-sm-8">
<div class="col-sm-12 right_column">{{source}}</div>
<button class="btn btn-primary" ng-click="update()">Submit Changes</button>
</div>
<div class="col-sm-4">
<div class="col-sm-4 drag_item_1"></div>
<div class="col-sm-4 drag_item_2"></div>
<div class="col-sm-4 drag_item_3"></div>
</div>
</div>
angular.module('app', ['ui.router'])
.config(['$urlRouterProvider', '$stateProvider',
function($urlRouterProvider, $stateProvider){
$urlRouterProvider.otherwise('/');
$stateProvider.state('homepage', {
url: "/",
templateUrl: "templates/homepage.html"
})
}])
.controller('swap_ctrl', function(){
$scope.source = "can it work?";
$scope.update = function() {
angular.copy($scope.source, $scope.master);
};
});
I know the code above doesnt work. It was just an attempt at trying to understand angular.copy. But it should give you an idea behind the structure. I was just going to use dragula to handle the dragging of objects to the right column.
I don't know how your actual code looks like, but let's assume you have two arrays that represent your columns:
$scope.columnsLeft = [...];
$scope.columnsRight = [...];
And view markup looks like this:
<div ng-repeat="column in columnsLeft track by $index"></div>
<div ng-repeat="column in columnsRight track by $index" ng-click="copyColumnToTheLeft(column, $index)"></div>
The ng-click could be inside the div element and it could be applied to the button. Then the method copyColumnToTheLeft which will copy our column could look like this:
$scope.copyColumnToTheLeft = function (column, index) {
$scope.columnsLeft[index] = angular.copy(column);
};
Using angular.copy will create a copy of the column passed to the method, so changing the column (in right array) in future will not immediately show the changes on the left panel, since it would be a different object.
Hope this helps.
UPDATE: In your particular case, you are going to have 2 arrays, one is master and second one is source:
$scope.master = [...];
$scope.source = [...];
If you are going to modify source array using dnd then your update method could look like:
$scope.update (){ $scope.master = angular.copy($scope.source); };
Anyway a good example of how it works is on the official docs page.
I'm new to AngularJS and having to work on an app that has a section of nested ngRepeats such as this below.
<div class="title-bar" ng-repeat="orderType in someObj.orderTypes">
<div class="inner-panel" ng-repeat="status in orderType.statuses">
<p>{{status.Name}}</p>
<div class="order-list" ng-repeat="order in status.Orders | limitTo:orderFilterLimit">
<p>{{order.Stuff}}</p>
</div>
<button ng-show="(status.Orders.length > orderFilterLimit)" ng-click="loadMoreOrdersToList()">Load More</button>
</div>
</div>
The status.Orders list can be quite large at times so I limit it. When a user wants to view more data for that specific section (which is enumerated by status) I add 3 to the orderFilterLimit. The problem is when I do this it is adding 3 to every single .order-list in the .inner-pannel element. Is there a way I can change the orderFilerLimit variable based on an id or class of the element it's attached to?
For context here is a super simple snippet of what loadMoreOrdersToList() is doing.
https://jsbin.com/vapucixesa/1/edit?js
No need of declare the orderFilterLimit inside controller, You should have scope variable inside ng-repeat itself so that it ng-repeat element will have separate copy of orderFilterLimit because ng-repeat create a child scope on each iteration.
Markup
<div class="title-bar" ng-repeat="orderType in someObj.orderTypes" ng-init="orderFilterLimit = 3">
<div class="inner-panel" ng-repeat="status in orderType.statuses">
<p>{{status.Name}}</p>
<div class="order-list" ng-repeat="order in status.Orders | limitTo:orderFilterLimit">
<p>{{order.Stuff}}</p>
</div>
<button ng-show="(status.Orders.length > orderFilterLimit)" ng-click="orderFilterLimit = orderFilterLimit + 3">Load More</button>
</div>
</div>
I am trying to apply the filters on the ng-repeat based on user selection in section options.But unable to do that so far.
Update-It works !!
Here's Plunker
HTML
<div class="container">
<div ng-include="" src="'refiners.html'"></div>
<br />
<br />
<div class="row">
<div class="col-xs-12">
<ul>
<li ng-repeat="item in data.Results | filter:cc">
<div>
<p>{{item.Title}}</p>
<p>{{item.City}}</p>
<p>{{item.PostalCode}}</p>
<span>{{item.MinimumSalePrice | currency}}</span>
<span>{{item.MaximumSalePrice |currency}}</span>
<p>{{item.PropertyType}}</p>
<p>{{item.TenureType}}</p>
</div>
</li>
</ul>
</div>
When you do ng-include you create a new scope so cc is always empty in the parent scope.
This is similar to the issue in this in question. AngularJS - losing scope when using ng-include
You can fix it by adding $scope.cc={} to your controller (creating this element in the parent $scope so the filter has access to it. For this to work you will have to remove the ng-init calls from refiners.html, since these will create a new object in the child scope.
This problem is a bit hard to explain, but I'll give it a try. When I'm using a nested view inside an ItemView of a CollectionView the next ItemView will append inside the previous childView.
<div id="items">
{{#collection}}
<div class="item">
{{title}}
{{view childView}}
</div>
{{/collection}}
</div>
Results in:
<div id="items">
<div class="item">
The title
<div class="childView">
This is the childView..
<div class="item">
The title
<div class="childView">
This is the childView..
</div>
</div>
// And so on...
</div>
</div>
</div>
It looks like the collectionView is keeping a reference to the last view there was something inserted into. So in this case the childView of the itemView, but it should be the itemView.
I hope I made myself a bit clear, because it is frustrating.
This looks like a known thorax bug that was closed.
I would double check your templates and make sure all your html elements have closing tags. Also get the latest version of thorax (assuming there are no breaking changes). It could be that the bug was closed incorrectly and still a problem.