onclick on hyperlink should add a div horizontally using angularjs - angularjs

My html:
<div id="contentDiv">
<div id="headerDiv" ><div id="titleDiv"> Queries</div></div>
<div id="valuesDiv" ><div id="yearDiv"> 2015</div></div>
<div id="graphDiv" ><div id="chartDiv">graph</div></div>
</div>
Like this div, I have another div but the content in the div is different.
How to add a new div horizontally when I click on hyperlink using angularjs?
How can I do this? please help me out regarding this

Looks like what you need is a two way binding with the ng-model directive. So the idea would be that you bind the new div to a variable in your scope which is initially in an empty or undefined state (for example, there are better ways). When the hyperlink is clicked it calls the function specified by an ng-click directive which will fill your bound object, which in turn will cause the new div to be rendered.
EDIT:
Based on your comments here is a simple example.
HTML page:
<div id="newDiv" ng-repeat="item in items">
<!-- Div content -->
<!-- example -->
<input type="text" ng-model="item.name">
</div>
<input type="button" ng-click="addItem()">
Controller:
$scope.items=[];
$scope.addItem = function() {
var newItem = {};
newItem.name = "new item name";
$scope.items.push(newItem);
}
What's happening here is the data for each div is stored in an array of objects. The ng-repeat directive will repeat the div for each object in the array. You can then fill the elements in the div using the object. Adding a new div is as simple as adding a new item to the array and angular will take care of the rest for you. Please note that I have not tested this example, but hopefully it's enough to point you in the right direction.
RE aligning the divs horizontally, this will be done with CSS, using the inline-block display mode. So you could give the div a class of, for example, "horizontalDiv" and add the following class to your CSS file:
.horizontalDiv {
display: inline-block;
}

Related

Changing the CSS of a div in AngularJS directive

I have a problem I have created a directive which is doing ng-repeat on an array of objects
---Showing the value on gui------
Now I want that if I click on any div of this repeat that particular div's background color should change
I have tried something like this
link:function(scope,element,attributes){
$(element).on('click',function(e){
$(element).addClass('A');
$(element).removeClass('B');
})
}
You can use the ng-class directive to apply classes on specific occurences, in your case in combination with the ng-click:
<div ng-repeat="item in items"
ng-class="{A: item.clicked, B: !item.clicked}"
ng-click="item.clicked = !item.clicked">
<!-- .. content -->
</div>
See this jsfiddle for example
You can try something like this, but this will need more workaround.
<div ng-click=“changeBackground($event)”></div>
// In Controller
$scope.changeBackground = function(event){
event.target.style.background = “#000”;
}
It would be better if you can submit your code.

AngularJS - One controller on two sibling DOM elements

I'm trying to do a very simple thing. I'm displaying a list of values with Edit links beside them. Clicking the edit link reveals a form that lets you update the value.
(I've simplified the question so the items just have one field "name". My actual use case has more fields, but is canonically equivalent.)
I've run into something that looks like a bug in Angular, but given my limited experience with it, I'm not so sure. Here's how I'm trying to do it:
<div ng-repeat-start="item in items" ng-controller="ItemCtrl as ctrl" ng-hide="ctrl.isEditing">
<span>Name: {{item.name}}.</span>
<a href='#' ng-click='ctrl.startEditing()'>Edit</a>
</div>
<div ng-repeat-end ng-show="ctrl.isEditing">
<input type='text' ng-model='item.name'/>
<a href='#' ng-click='ctrl.save()'>Save</a>
</div>
My controller looks like this:
app.controller('ItemController', function() {
this.isEditing = false;
this.startEditing = function() { this.isEditing = true; }
this.save = function() { this.isEditing = false; }
});
Clicking on Edit link calls the right controller function, and the first div hides. But the second div does not hide.
When I rearrange the code to look like this (essentially wrapping the two divs with a wrapper element), all is well.
<div ng-repeat="item in items" ng-controller="ItemCtrl as ctrl">
<div ng-hide="ctrl.isEditing">
<span>Name: {{item.name}}.</span>
<a href='#' ng-click='ctrl.startEditing()'>Edit</a>
</div>
<div ng-show="ctrl.isEditing">
<input type='text' ng-model='item.name'/>
<a href='#' ng-click='ctrl.save()'>Save</a>
</div>
</div>
Any idea what is technically wrong with the first version? Note that the <input> boxes do get populated with the right values from item.name.
PS: There's a reason why I'm trying to keep the two divs siblings: in my use case, they are actually implemented as two trs which are supposed to appear right below each other in a table.
It's not a bug from angular but it is quite logical.
<div ng-repeat-start="item in items" ng-controller="ItemCtrl as ctrl" ng-hide="ctrl.isEditing">
<span>Name: {{item.name}}.</span>
<a href='#' ng-click='ctrl.startEditing()'>Edit</a>
</div>
<div ng-repeat-end ng-show="ctrl.isEditing">
<input type='text' ng-model='item.name'/>
<a href='#' ng-click='ctrl.save()'>Save</a>
</div>
If you see the above code you have injected controller only to the first div so obviously sibling div doesn't know what is ctrl or ItemCtrl until and unless you do as in you second way.
So if you want to achieve it as sibling, if you are using routing then add the controller attribute in your route path.
So that the controller will be active for that entire template and you can achieve what you want.
Hope it helps.
Thats because controller has its own scope. When you placed controller ONLY on your first div controllers' scope is limited to only this one div. When you wrapped both your divs inside another and place controller on wrapper, controllers' scope now is all that inside this wrapper. So in this case this works fine and this is not the angular bug

AngularJS - Add DOM elements on counter++

I'm quite new to AngularJS and have read a little bit about how directives work. I'm still not quite sure about how to go about this problem though.
Here's the setup:
I have buttons on a view like so:
<div class="parent">
<button class="firstButton" type="button" ng-click="fetchData(param1, param2)"></button>
<button class="secondButton" type="button" ng-click="fetchData(param1, param2)"></button>
<button class="thirdButton" type="button" ng-click="fetchData(param1, param2)"></button>
<button class="fourthButton" type="button" ng-click="fetchData(param1, param2)"></button>
</div>
<div class="dataPanel">
<!-- This is where DIVs will be placed -->
</div>
Then in my controller I have:
// Init value of counter here
var counter = 0;
$scope.fetchData = function (param1, param2) {
// Do something with parameters here
counter++;
}
Ideal scenario would be when user clicks on firstButton, fetchData() initiates, getting data from a factory, then increments value of counter. A div would be created from counter value change. The number of divs created in the DOM would depend on counter value. Each created div is also populated with data gotten from each respective fetchData(). This goes on as user clicks on more buttons, although in my current project, I've limited the number of allowed dataSet duplicates.
End result of the HTML would then be:
<div class="dataPanel">
<div class="dataSet"> <!-- from firstButton -->
<p>{{dataFromFirstButton}}</p>
</div>
<div class="dataSet"> <!-- from secondButton -->
<p>{{dataFromSecondButton}}</p>
</div>
<div class="dataSet"> <!-- from thirdButton-->
<p>{{dataFromThirdButton}}</p>
</div>
</div>
What's the Angular way of doing this? I've read directives can pretty much do everything when it comes to DOM manipulation but have no idea on where to start when it comes to actually constructing the directive.
One way to accomplish this is to use ng-repeat directive to draw the divs based on an array, that is initially empty. You can set the html up so that a div is drawn for each object in the array, since the array is empty no div is initially drawn.
<div class="dataSet" ng-repeat="n in arrays[0]">
This div from button 1 contains: {{n.data}}
</div>
When you click on the buttons you can add an object, containing any needed data, to the array. Then a div will be drawn for the appropriate ng-repeat directive.
$scope.arrays = [ [], [], [], []];
$scope.fetchData = function (data, idx) {
$scope.arrays[idx].push({data: data});
}
See plunker here.

How to set focus on last element in ng-repeat?

I display a list of items through ng-repeat
<div ng-repeat="{item in items}" >
<h3>{{item.name}}</h3>
<h3>{{item.price}}</h3>
<h3>{{item.date}}</h3>
</div>
I have an add where i click and add new items..I display through ng-repeat in a div and that contains scroll..Whenever i add a new item the scroll bar stand still and i can see the newly added item by scrolling down only.
I used ng-focus="{$last}" to set focus on last item but it didnt work.
I need to set focus on last element in ng-repeat even i have 50 elements in div.
Plss help me in this..
I'd recommed using a directive to achieve this behaviour.
module.directive('setFocus', function(){
return{
scope: {setFocus: '='},
link: function(scope, element){
if(scope.setFocus) element[0].focus();
}
};
});
And on your HTML:
<div ng-repeat="{item in items}" set-focus="$last">
<h3>{{item.name}}</h3>
<h3>{{item.price}}</h3>
<h3>{{item.date}}</h3>
</div>
When you load the page, .focus() is ran on the last element.
If you add an element, .focus() is ran on that new last element.
Now your problem lies on which elements are focusable across different browsers. I suggest you check which HTMLElement can receive focus.
So, you may want to add a hidden focusable element inside your div, and modify the directive to focus on that, or maybe add a tabindex attribute to your ng-repeat div. (tabindex="some number other than -1")
<div ng-repeat="{item in items}" set-focus="$last" tabindex="0">
<h3>{{item.name}}</h3>
<h3>{{item.price}}</h3>
<h3>{{item.date}}</h3>
</div>
I hope this helps!
To clarify: ng-focus is used to specify behaviour ON focus, not to trigger focus on the element.
You can use $anchorScroll in AngularJS.
Just place a link (< a> < /a>) at the bottom of your div with the id="bottom" and ng-hide="true", so you dont actually see the link.
<div id="scrollArea" ng-repeat="item in items">
<h3>{{item.name}}</h3>
<h3>{{item.price}}</h3>
<h3>{{item.date}}</h3>
<a id="bottom"></a>
</div>
<button type="button" ng-click="addNewItem" value="Add"/>
When you click on your "add" button or whatever, call a function in the Controller that leads you to the bottom link with the id="bottom".
$scope.addNewItem = function() {
//Add new item here...
//After adding item, go to bottom:
$location.hash('bottom');
$anchorScroll();
};
You can read more about this on the Documentaion of AngularJS:
Documentaion of $anchorScroll.

Angularjs: custom grid component, dynamically add <br> elements

Ok, I have made a really simple grid component. I fetch a column count attribute and add a <br> tag after the end of a row. I do that within the link function.
Her is the directive: http://pastebin.com/U4ckuKJw
grid.html just looks like this: <div class="grid" data-ng-transclude=""></div>
In my first example I have 7 <div> tags inside the grid component and want to have 3 columns. So after every third <div> I want a <br> to be added.
It looks like this and is working:
<div data-grid="" data-cols="5">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
</div>
This one is not working: http://pastebin.com/wtcgM2Hv
I think it is because of the directive ng-repeat and that the content of the grid component isn't rendered at the time the link function ist executed.
Any thoughts on how to solve this problem or how to optimise the component?
An easier approach may be to solve the problem with standard angular directives and css. For instance, if you float your cells and clear: left on those cells that start a new row, you can use ng-repeat and ng-class to accomplish this.
I created an example at: http://jsbin.com/idukaz/1
The html looks like this. Note I'm using ng-class to apply the class that formats the cell that needs to start a new row depending on the result of calling the custom columnEnd function. columnBreak is a scope variable for the number of columns you want. $index is a variable generated by ng-repeat:
<div class="table">
<div class="label"
ng-class="{'new-row': startNewRow($index, columnBreak) }"
ng-repeat="item in items">{{ item.name }} ({{ $index + 1 }})</div>
</div>
In your controller:
app.controller('Controller', ['$scope', function (scope) {
// list of grid data
scope.items = [];
// controls the number of columns
scope.columnBreak = 5;
// calculates if current cell is start of new row
scope.startNewRow = function (index, count) {
return ((index) % count) === 0;
};
}]);
In your css if you float your cells and clear left, you'll get your columns to dynamically
reformat when you change the columnBreak value.
.label {
float: left;
}
.new-row {
clear: left;
}
Ok, now I found the solution:
use angular directive to change classes of ng-repeat elements
I mixed it with Marks idea and manipulate the css classes now.
Thanks

Resources