How to do inline editing in angularjs without Template? - angularjs

am trying to write an inline editing function without using a template as outlined here
http://plnkr.co/edit/EsW7mV?p=preview

You can just place the code of the template in the main page.
<li ng-repeat="todo in todos" inline-edit="todo.title" on-save="updateTodo(todo.title)" on-cancel="cancelEdit(todo.title)">
<div>
<input type="text" on-enter="save()" on-esc="cancel()" ng-model="model" ng-show="editMode">
<button ng-click="cancel()" ng-show="editMode">cancel</button>
<button ng-click="save()" ng-show="editMode">save</button>
<span ng-mouseenter="showEdit = true" ng-mouseleave="showEdit = false">
<span ng-hide="editMode" ng-click="edit()">{{model}}</span>
<a ng-show="showEdit" ng-click="edit()">edit</a>
</span>
</div>
</li>
Here there is a fiddle:
http://jsfiddle.net/siliconball/QwDn9/2/
Also temeber to take away the templateUrl: 'inline-edit.html'
If you need the controller scope for any reason place scope: false in the directive. But then you will have to track which option are you editing in any moment (maybe using the id). If that is your situation i suggest to refactor a bit, as you may know, probably is not the best option.
If your situation, i guess it is, is that you want to write it all in one page because you are generating it through some CGI or dynamic content script and you don't want to write the same code in different pages (+scripts interfaces ...), then i suggest also to move the inline-edit="todo.title" and all the directive stuff in the <div> for the sake of orthogonality.

Related

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

How to add ngClick to an existing element

So I have some HTML that I do not control.
<div id="myDiv">
Stuff inside my div...
</div>
I want to add an ngClick to it. If I could control the html, I would just do this
<div id="myDiv" ng-click="doSomething()">
Stuff inside my div...
</div>
But like I said, I can't change the html. If this was jQuery, I would just do
$('#myDiv').click(function(){
doSomething();
});
How do I do this in Angularjs? Thanks.
UPDATE
Judging from the downvotes, it seems like you guys are not happy with what I am trying to do here, so let me explain.
I am using AngularUI in my app. AngularUI has all these templates that they insert. For example
<accordion-heading></accordion-heading>
becomes
<div class="panel-heading">
<h4 class="panel-title">
<a href="" class="accordion-toggle" ng-click="toggleOpen()" accordion-transclude="heading">
<span class="ng-binding ng-scope">Heading</span>
</a>
</h4>
</div>
I want to add ngClick to "panel-title". I COULD overwrite the template and add it, but I don't want to do that. Coming from jQuery, it makes sense to just listen to a click event on "panel-title". How it is done Angular? Thanks.
You need to find the element, smth like: angular.element(//selector here); then add attribute you need(ng-click), .attr('ng-click', '//whatever should be here'), and then compile it with angular $compile.
But. I feel sad that you have to do this, I hope you'll find a possibility to change html.
Docs for compile

How to ng-include at click on link

I'm new on AngularJS and I need to include another template by clicking on a link.
I have a nav.html and a header.html. Both included in the index.html.
In header.html I have
<li class="search-box visible-md visible-lg" data-ng-include=" 'views/calls/search.html' ">
calls/search.html
<div class="input-group" data-ng-controller="callSearchCtrl">
<span class="input-group-addon"><i class="fa fa-search text-muted"></i></span>
<input type="text" class="form-control" placeholder="Suchen..."></div>
And I have to include another template in the header by clicking on a menu point (i.e. Contacts) to load the contacts/search.html
<div class="input-group" data-ng-controller="contactsSearchCtrl">
<span class="input-group-addon"><i class="fa fa-search text-muted"></i></span>
<input type="text" class="form-control" placeholder="Suchen..."></div>
to get another search controller.
The case is, that I have a search bar in the header, where I want to search in the loaded content template.
Maybe I've got the wrong mindset to solve this...
Anyone knows a solution?
ADDITION:
Now I put different ng-clicks in my nav like:
<i class="fa fa-users"></i><span>Kontakte</span>
But do I have to put the scope function in my HeaderCtrl or in my NavCtrl?
P.S. Sorry for my bad english :-)
Cheers
bambamboole
The simplest and probably most idiomatic is as #coder-john suggests.
data-ng-include="search.option"
In your controller,
$scope.search = {};
$scope.selectType = function (type) {
$scope.search.option = 'views/'+type+'/search.html';
};
$scope.selectType('calls');
where your menu options should invoke the proper handlers, such as
data-ng-click="selectType('calls')"
or
data-ng-click="selectType('contacts')"
as appropriate.

Directive that creates child scope in AngularJS

When creating complex forms I found the need of separating some parts of my view into different child scopes to be able to have individual visual properties.
The good example could be implementing 'click-to-edit' behaviour: when you have one html to view something and another to edit.
One of the solution is to create en directive that will have isolated scope. But in case if html markup for different properties differs a lot, you need to have kind of "double transclusion" (manually compile templates upon switching).
So more simplier is to have some small copy-pasting, but show dirrectly what is going on with view. This simplifies markup a lot.
Here is a sample code that illustrates that problem:
<span class="editable" >
<span ng-hide="editing">
{{user.first}} <span ng-click="editing = true"><i class="icon-pencil"></i></span>
</span>
<span ng-show="editing">
<input type="text" ng-model="user.first">
<span ng-click="editing = false"><i class="icon-ok"></i></span>
</span>
</span>
<span class="editable" >
<span ng-hide="editing">
{{user.last}} <span ng-click="editing = true"><i class="icon-pencil"></i></span>
</span>
<span ng-show="editing">
<input type="text" ng-model="user.last">
<span ng-click="editing = false"><i class="icon-ok"></i></span>
</span>
</span>
In this scenario 'child scopes' is first that come into mind.
But I didn't found directive that simply creates new scope in AngularJS. Is there a one?
As one of the very straight solution I've wrote an simple one-line directive:
.directive('childScope', function() {
return { scope: true, restrict:'AE' }
});
And use it just adding to <span class="editable" child-scope> in my source example.
But may be there is some standard directive for doing that?
If not, I consider this solution could be usefull for others.

CRUD detail screen, conditional new or edit

I'm working on a CRUD detail screen in Angular and wish to reuse a single template. Here's the initial template psuedo-code, the crude beginnings of an edit screen...
<h1>{{fixtureType.Label}}</h1>
<form>
<span>Fixture Type Details</span>
<label>Type</label>
<input>{{fixtureType.Type}}</input>
<label>Watts</label>
<input>{{fixtureType.Watts}}</input>
<label>Cost</label>
<input>{{fixtureType.Cost}}</input>
</form>
Suppose I want to conditionally use the same template as a new screen as well, that would look something like this
<h1>New Fixture Type</h1>
<form>
<span>Fixture Type Details</span>
<label>Type</label>
<input/>
<label>Watts</label>
<input/>
<label>Cost</label>
<input/>
</form>
If this were straight Javascript, a simple condition like bIsEdit = fixtureType != null would do the trick. From what I've read so far there is no conditional or way to drop in a chunk of JS into an Angular view.., or is this where I reach for a custom directive or filter?
Now I could have 2 views and handle the routing appropriately, but would prefer to have a single one to avoid code duplication.
So what is the Angular way to handle something like this?
I would prefer separate routes for each. To keep the edit and new HTML together, you could use ng-switch with essentially two templates, but consider putting them both into one partial, so you can ng-include it in the two different views:
<span ng-switch on="mode">
<span ng-switch-when="edit">
<h1>{{fixtureType.Label}}</h1>
<form>
<span>Fixture Type Details</span>
<label>Type</label>
<input ng-model='fixtureType.Type' ...>
...
</span>
<span ng-switch-default>
<h1>New Fixture Type</h1>
<form>
<span>Fixture Type Details</span>
<label>Type</label>
<input ng-model="fixtureType.Type" ...>
...
</span>
</span>
I use following approach to minimize form duplication when differences between new and editable versions aren't too complex:
<form ng-submit="mySubmitMethod()">
<!-- fields models bound to "activeItem"-->
<button >
<span ng-show="editMode>Update</span>
<span ng-show="!editMode">Create</span>
</button>
</form>
$scope.activeItem={};
$scope.editMode=false;
$scope.mySubmitMethod=function(){
if($scope.editMode){
/* do update of existing*/
}else{
/* process new form*/
}
$scope.resetform()
});
$scope.EditUser=function(user){
$scope.editMode=true;
$scope.activeItem=angular.copy( user);
})
$scope.newUser=function(){
$scope.editMode=false;
$scope.activeItem={};
})

Resources