if it's jquery, we can do like $('table-row').clone().preprenTo($('table'));
I know it's just push a new value into an object in adding new data but I want to first insert the empty row and field first, how to add that html with angularjs?
John added a link to a famous question/answer regarding AngularJS. I would advice you to read that.
That said, to answer your question - in angular you do not tell it how to manipulate the dom. You tell it what data you have and how you want it presented.
I can only guess to what you are trying to do, but if you have a template (your 'table-row') and a 'destination' ('table') you would describe it in AngularJS like this:
<table ng-controller="PersonsController">
<tr ng-repeat="person in persons">
<td>{{person.Name}}</td>
<td>{{person.Address}}</td>
</tr>
</table>
That is great, but how do you add a row? Well you don't "add a row" - you add a person and AngularJS will do the adding of rows for you. You already explained how you want a person displayed.
To add a person you would have to add a person to a list/array of persons and that list would be in the scope of your view/application.
persons.push({Name: 'Bill', Address: 'Somewhere'});
You will need to attach the persons to your scope, which you will do in a controller. A controller would have to be associated with the code above with the ng-controller directive.
app.controller('PersonsController', function ($scope) {
$scope.persons = [];
});
In the above code i assume you have a variable app pointing to your angular application. There is a small learning curve you will have to overcome, going from jquery to angular. Mostly, the way i see it, is moving your mindset from a imperative coding style to a declarative coding style.
I suspect you need a paradigm shift. Read "Thinking in AngularJS" if I have a jQuery background.
Then, if you still think that your problem is best solved by adding a row to the DOM, consider using an AngularJS directive.
Related
I've been a C/C++ coder for a long time, but am new to Angular2 and TypeScript. I have a TypeScript class (call it Node) which has a type: string property that specifies what sort of node it is. (The data comes as JSON from a server, and is basically being parsed out as a syntax tree.)
What I'm doing now in the view template in order to choose the view for each Node object is using an ngSwitch to check the value of node.type, and then inserting the appropriate selector using ngSwitchCase for each possible case, e.g.:
<div [ngSwitch]="node.type">
<node-type-a-view *ngSwitchCase="'a'" [(node)]="node"></node-type-a-view>
<node-type-b-view *ngSwitchCase="'b'" [(node)]="node"></node-type-a-view>
<node-type-c-view *ngSwitchCase="'c'" [(node)]="node"></node-type-a-view>
<div class="debug" *ngSwitchDefault>
TODO: View for type "{{node.type}}" is missing
</div>
</div>
The problem is that there are over a hundred different node types, and so this is going to be very unwieldy, very quickly.
What I'd like to do is something like this (but obviously this doesn't work in Angular2):
<node-type-{{node.type}}-view [(node)]="node"></node-type-{{node.type}}-view>
Or, using an attribute selector:
<div node-type-{{node.type}}-view [(node)]="node"></div>
Is there any functionality that comes close to what I'm looking for? I don't need to dynamically create the node-type-*-view views themselves, just the template that references them.
Also, apologies if I'm getting this architecture completely wrong. I'm still wrapping my head around the way Angular2 does things!
Thanks for any assistance you can give!
I'm using Angular 1.x and I have a section of code that I'm looking to repeat quite a bit, so I wanna throw it in a directive. The trouble is, it's somewhat complicated and I'm not sure how to begin writing it.
Essentially, it's a section of the page that displays various card directive and with infinite scrolling and perfect scrollbar.
<perfect-scrollbar refresh-on-change="myScope.data">
<div class="limit-columns">
<masonry masonry-options="{gutter: 30, isFitWidth: true}">
<user-card class="masonry-brick" ng-repeat="item in myScope.data"></user-card>
</masonry>
<div class="infinite-scroller" infinite-scroll="myScope.showMore()" infinite-scroll-tolerance="5"></div>
</div>
</perfect-scrollbar>
Perfect-scrollbar and masonry are both angular libraries on GitHub. Infinite-scroller is one I wrote myself, but works as you'd expect.
myScope contains a data attribute that is a list of objects containing a card's data. myScope.showMore is a function that adds items to that myScope.data list. Perfect-scrollbar also takes the refresh-on-change attribute which watches for changes on a particular object, in this case the list.
Ideally my directive would look something like this:
<card-scroller gutter="30" tolerance="5">
<some-card ng-repeat="achievements.data"></some-card>
</card-scroller>
But I'm not sure how feasible this is. Thanks!
In my Meteor template, I am using each to iterate over a helper array variable named asks whose array contents are dynamically changing. This is displaying properly in Meteor, however, by default, there is no animation to it. The changes are sudden, so it's hard to see exactly what is changing when. I would like to animate these data changes in the template. If asks[1] is the same, do nothing. But if asks[2] has changed, fade out the old <tr> for asks[2] and fade in the new <tr> with the new asks[2] values. How can this be achieved? Thanks!
{{#each asks}}
<tr class="ask">
<td>{{price}}</td>
<td>{{amount}}</td>
</tr>
{{/each}}
Use the _uihooks - here's a great article describing it:
http://www.webtempest.com/meteorjs-animation
Also, this package may be of help: https://github.com/gwendall/meteor-template-animations It is DOM based and internally uses uiHooks, but simpler to use.
Another option added to the mix for animations, which imports Animate.css can be found here https://github.com/webtempest/meteor-animate.
I'm fairly new to Angular JS and I'm trying to create a datepicker directive. It will not work like the Angular UI Bootstrap datepicker as it won't use a textbox but a full page calendar which you will be able to swipe through and click a day (which will update ngModel).
My plan was to have a single directive which has a renderMonth() function. This function would accept a month as a parameter and generate all the rows/days in an array which would then be bound to a template for the month.
My problem is that I can specify a template for the datepicker in my directive declaration but I don't know how to specify templates for the rows/days etc and load them in and bind them. I could do it using jQuery and lots of string concetenation, but that seems all wrong.
I have been reading the source code for the Angular UI Datepicker but as a newbie it makes very little sense to me. They have decoupled everything into many sub-directives (month directive, year directive etc.) and they have their own templates, but that's not what I want to do because my Angular skills aren't going to stretch to creating directives which communicate with each other. The Angular UI code is just way too complicated for me.
One thing I do like is that they use existing directives like ng-repeat in their templates and bind them to the array or rows/days. For me to do that I'd need to load the template in each time the renderMonth() is called and compile the template because it has existing directives in it.
So, basically my question is, does anybody have any examples of how I could write a import a template into my render function, compile it and ten bind it to the row/day data which is in my directives scope.
I'll be honest. I have no idea if I'm even speaking any sense. I'm just typing words which sound vaguely right.
ALl I need is for somebody to point me in the right direction. Thanks.
As discussed in the comments, I personally wouldn't worry too much about importing templates, the $compile function, or anything that complex for what is relatively simple markup.
I've created a (very) basic barebones plunker here, to demonstrate what my approach would be. I've used moment.js to deal with dates, because I am terrible with vanilla javascript date manipulation and find it very clumsy.
This is the template:
<div class="controls">
<button ng-click="prevMonth()"><-</button>
<span>{{selected.format('MMMM')}}</span>
<button ng-click="nextMonth()">-></button>
</div>
<div class="month">
<span class="day" ng-repeat="day in selected.days">
{{day.number}}
</span>
</div>
The template relies on the scope having a selected property which is a moment object. All it does is creates some buttons change the month and displays the month name at the top, then creates a span for each day in that month.
A tiny bit of CSS puts the days in rows of 7:
span.day{
float: left;
width: 25px;
}
span.day:nth-child(7n+1){
clear:left;
}
This is the directive's link function:
link: function(scope, element, attributes){
// Set the selection to now initially.
scope.selected = moment();
generateDaysArray = function(){
// -- REMOVED FOR BREVITY -- //
return days;
}
// Watch the month for changes and update the days array
scope.$watch(
function(){
return scope.selected.month();
},
function(newVal, oldVal){
scope.selected.days = generateDaysArray();
}
)
// Control button actions
scope.nextMonth = function(){
scope.selected.add('month', 1)
}
scope.prevMonth = function(){
scope.selected.subtract('month', 1)
}
}
There is really nothing special there, but do note that the $watch command used takes advantage of the fact that you can pass a function instead of a string (though looking at it now you could just use 'selected.month()' as a string).
Generating the days array is slightly more complex if you want to align the dates with days of the week, which I started to do, but didn't finish. My plan was for each object in the array to have a isPreviousMonth property which would conditionally apply a different style using ng-class, and would look up the correct number as well, rather than just using a ~ for the offset days!
There is a lot more to do to finish this off - not least making the dates selectable and integrating with ngModel, but hopefully this example has given you an idea of one way to approach the problem of templating. There are many other ways you could do this, but I find this the most intuitive.
Extension
To address your question regarding having multiple months, I've expanded the plunker a bit.
I added an attribute to the directive:
<date-picker num-months="3"></date-picker>
And modified the template to ng-repeat certain parts depending on the number of months you specify in the attribute:
<div class="controls">
<button ng-click="prevMonth()"><-</button>
<span ng-repeat="month in months" class="month-title">
{{month.moment.format('MMMM')}}
</span>
<button ng-click="nextMonth()">-></button>
</div>
<div class="month" ng-repeat="month in months">
<span class="day" ng-repeat="day in month.days">
{{day.number}}
</span>
</div>
So this instead requires an array of months, each with 2 properties: a moment, and an array of days. I added some quick and dirty javascript to generate that, but I won't paste it here as there are almost certainly much neater ways of doing it!
Note that at present we're still watching scope.selected for changes in the month, which would lead to the (probably unwanted) behaviour that if you selected a date not in the first month, the calendar would rearrange itself. I think instead of using a $watch in this case, I'd just add to the click events to handle redrawing the calendar properly.
PS This addresses the cloning part but not the scrolling part. For scrolling, I would recommend adding one extra month on either end of the months array, then having an ng-show condition that means only the middle month(s) is shown. You can then take advantage of angular's inbuilt animations (this is a good reference) to scroll them in/out using css. If you want more info about that contact me through the chat I opened for this question.
I want to do something similar to a $routeProvider .when but instead of using URL I would like to load an HTML file and a new controller based on a variable change.
Assume I use a $http polling and the poll has a variable that changes, and I would like to change the Controller and template based on that. What is the best strategy for this
I'm new to this so please excuse if this is a stupid question.
Thank you so much.
The first thing that comes to mind is you could do something like this
<div>
<directive1 ng-if="switch_var == val_1"></directive1>
<directive2 ng-if="switch_var == val_2"></directive2>
...
</div>
Create a directive for each template/controller combo you want, and then choose which directive to show based on your poll variable.
Alternative to using a bunch of ng-if's, use ng-switch - http://docs.angularjs.org/api/ng/directive/ngSwitch