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={};
})
Related
I am new to AngularJS.
I have created <li> to which I used ng-repeat.
<li> contains images and buttons like like, comment and share which is inside <li> and created by ng-repeat.
I have made function which will replace empty like button to filled like button (By changing background image of button).
But problem is this trigger applies to only first like button and other buttons does not change.
How can I fix this?
Code:
HTML:
<html>
<body>
<ul>
<li ng-repeat="media in images"><div class="imgsub">
<label class="usrlabel">Username</label>
<div class="imagedb">
<input type="hidden" value="{{media.id}}">
<img ng-src="{{ media.imgurl }}" alt="Your photos"/>
</div>
<!-- <br><hr width="50%"> -->
<div class="desc">
<p>{{media.alt}}</p>
<input type="button" class="likebutton" id="likeb" ng-click="like(media.id)" ng-dblclick="dislike(media .id)"/>
<input type="button" class="commentbutton"/>
<input type="button" class="sharebutton"/>
</div>
</div> <br>
</li><br><br><br>
</ul>
</body>
</html>
JS:
$scope.like = function(imgid)
{
document.
getElementById("likeb").
style.backgroundImage = "url(src/assets/like-filled.png)";
alert(imgid);
}
$scope.dislike = function(imgid)
{
document.
getElementById("likeb").
style.backgroundImage = "url(src/assets/like-empty.png)";
}
Thanks for help & suggestions :)
The id for each button should be unique but in your case, it's the same for all buttons ('likeb').
You can set the value of the attribute 'id' for each button dynamically by using '$index' and passing '$index' to the functions as follows:
<input type="button" class="likebutton" id="{{$index}}" ng-click="like($index)" ng-dblclick="dislike($index)"/>
Then in your controller, you can use the functions with the passed value.
For example,
$scope.like = function(index)
{
document.
getElementById(index).
style.backgroundImage = "url(src/assets/like-filled.png)";
}
Another good alternative in your case would be to use the directive ngClass.
use 2 css class for styling liked and disliked state, and then put the class conditionally with ng-class instead of DOM handling. and if you really want to perform a DOM operation (I will not recommend) then you can pass $event and style $event.currentTarget in order to perform some operation on that DOM object.
In code below when i click on "addNewEmp" i am creating new employee and adding it to the Employees model.
In my HTML i need to use $forms.['Form'+$index].$invalid.
But it shows the "undefined error" for newly created Emp form.
Please let me know if there is another way to define the Form Object?
<div ng-repeat=emp in employees>
<form name = forms.{{$index}}>
<button ng-click=addNewEmp() ng-disabled={forms[$index].$invalid}}/>
<form>
</div>
Your should access form object like below if you have array of forms.
<form name="forms[$index]">
Inside ng-repeat use ng-form.
As in
<div ng-repeat="emp in Employees">
<div ng-form="currentItemForm">
<button ng-click="addNewEmp()"/>
</div>
</div>
All things like validation, etc will be independent for each item in the repeater.
If you want to get the state of all forms, you can have a <form> wrapper around the whole repeater as well.
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.
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.
all:
Is there a way to dynamically add a tag (especially a custom tag) in AngularJS?
I have a custom tag recently created of the type:
<mytag type="small" />
which I am attempting to manage in a larger <div> element. What I would like to do is place, within the div element, a button that, when pressed, causes the creation of a new mytag element within the div.
In other words, given an initial page composition:
<div ng-controller="tagControl">
<div id="tagdiv">
<mytag type="small" />
</div>
<div id="Controls">
<button ng-click="addTag()">Add New Tag</button>
<button ng-click="clearTags()">Clear All Tags</button>
</div>
</div>
I would like to put something in the tagControl's addTag() function that adds a new mytag tag whenever the "Add New Tag" button is pressed, and I'd like to put something in the clearTags() function that removes all added tags when the "Clear All Tags" button is pressed.
Is this possible using AngularJS? If not, can it be accomplished using a third- party library? In either event, how can this be done?
Thanks in advance for any insights...
You need to think in terms of MVC and not DOM manipulation. How many of your <mytag>s you want to show up should be driven by something in your model. And then your HTML would look like this:
<div ng-controller="tagControl">
<div id="tagdiv">
<mytag type="small" ng-repeat="foo in items" />
</div>
<div id="Controls">
<button ng-click="addTag()">Add New Tag</button>
<button ng-click="clearTags()">Clear All Tags</button>
</div>
</div>
Then your addTag() method would just add to the items model and the clearTags() would clear the list. Angular will add the tags for you as you update the model