I am trying to write a function that enables me to remove an item when the button is clicked but I think I am getting confused with the function - do I use $digest?
HTML & app.js:
<ul ng-repeat="bday in bdays">
<li>
<span ng-hide="editing" ng-click="editing = true">{{bday.name}} | {{bday.date}}</span>
<form ng-show="editing" ng-submit="editing = false">
<label>Name:</label>
<input type="text" ng-model="bday.name" placeholder="Name" ng-required/>
<label>Date:</label>
<input type="date" ng-model="bday.date" placeholder="Date" ng-required/>
<br/>
<button class="btn" type="submit">Save</button>
<a class="btn" ng-click="remove()">Delete</a>
</form>
</li>
</ul>
$scope.remove = function(){
$scope.newBirthday = $scope.$digest();
};
To remove item you need to remove it from array and can pass bday item to your remove function in markup. Then in controller look up the index of item and remove from array
<a class="btn" ng-click="remove(item)">Delete</a>
Then in controller:
$scope.remove = function(item) {
var index = $scope.bdays.indexOf(item);
$scope.bdays.splice(index, 1);
}
Angular will automatically detect the change to the bdays array and do the update of ng-repeat
DEMO: http://plnkr.co/edit/ZdShIA?p=preview
EDIT: If doing live updates with server would use a service you create using $resource to manage the array updates at same time it updates server
This is a correct answer:
<a class="btn" ng-click="remove($index)">Delete</a>
$scope.remove=function($index){
$scope.bdays.splice($index,1);
}
In #charlietfl's answer. I think it's wrong since you pass $index as paramter but you use the wish instead in controller. Correct me if I'm wrong :)
In case you're inside an ng-repeat
you could use a one liner option
<div ng-repeat="key in keywords">
<button ng-click="keywords.splice($index, 1)">
{{key.name}}
</button>
</div>
$index is used by angular to show current index of the array inside ng-repeat
Using $index works perfectly well in basic cases, and #charlietfl's answer is great. But sometimes, $index isn't enough.
Imagine you have a single array, which you're presenting in two different ng-repeat's. One of those ng-repeat's is filtered for objects that have a truthy property, and the other is filtered for a falsy property. Two different filtered arrays are being presented, which derive from a single original array. (Or, if it helps to visualize: perhaps you have a single array of people, and you want one ng-repeat for the women in that array, and another for the men in that same array.) Your goal: delete reliably from the original array, using information from the members of the filtered arrays.
In each of those filtered arrays, $index won't be the index of the item within the original array. It'll be the index in the filtered sub-array. So, you won't be able to tell the person's index in the original people array, you'll only know the $index from the women or men sub-array. Try to delete using that, and you'll have items disappearing from everywhere except where you wanted. What to do?
If you're lucky enough be using a data model includes a unique identifier for each object, then use that instead of $index, to find the object and splice it out of the main array. (Use my example below, but with that unique identifier.) But if you're not so lucky?
Angular actually augments each item in an ng-repeated array (in the main, original array) with a unique property called $$hashKey. You can search the original array for a match on the $$hashKey of the item you want to delete, and get rid of it that way.
Note that $$hashKey is an implementation detail, not included in the published API for ng-repeat. They could remove support for that property at any time. But probably not. :-)
$scope.deleteFilteredItem = function(hashKey, sourceArray){
angular.forEach(sourceArray, function(obj, index){
// sourceArray is a reference to the original array passed to ng-repeat,
// rather than the filtered version.
// 1. compare the target object's hashKey to the current member of the iterable:
if (obj.$$hashKey === hashKey) {
// remove the matching item from the array
sourceArray.splice(index, 1);
// and exit the loop right away
return;
};
});
}
Invoke with:
ng-click="deleteFilteredItem(item.$$hashKey, refToSourceArray)"
EDIT: Using a function like this, which keys on the $$hashKey instead of a model-specific property name, also has the significant added advantage of making this function reusable across different models and contexts. Provide it with your array reference, and your item reference, and it should just work.
I usually write in such style :
<a class="btn" ng-click="remove($index)">Delete</a>
$scope.remove = function(index){
$scope.[yourArray].splice(index, 1)
};
Hope this will help
You have to use a dot(.) between $scope and [yourArray]
Building on the accepted answer, this will work with ngRepeat, filterand handle expections better:
Controller:
vm.remove = function(item, array) {
var index = array.indexOf(item);
if(index>=0)
array.splice(index, 1);
}
View:
ng-click="vm.remove(item,$scope.bdays)"
implementation Without a Controller.
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<script>
var app = angular.module("myShoppingList", []);
</script>
<div ng-app="myShoppingList" ng-init="products = ['Milk','Bread','Cheese']">
<ul>
<li ng-repeat="x in products track by $index">{{x}}
<span ng-click="products.splice($index,1)">×</span>
</li>
</ul>
<input ng-model="addItem">
<button ng-click="products.push(addItem)">Add</button>
</div>
<p>Click the little x to remove an item from the shopping list.</p>
</body>
</html>
The splice() method adds/removes items to/from an array.
array.splice(index, howmanyitem(s), item_1, ....., item_n)
index:
Required. An integer that specifies at what position to add/remove items, Use negative values to specify the position from the end of the array.
howmanyitem(s): Optional. The number of items to be removed. If set to 0, no items will be removed.
item_1, ..., item_n: Optional. The new item(s) to be added to the array
I disagree that you should be calling a method on your controller. You should be using a service for any actual functionality, and you should be defining directives for any functionality for scalability and modularity, as well as assigning a click event which contains a call to the service which you inject into your directive.
So, for instance, on your HTML...
<a class="btn" ng-remove-birthday="$index">Delete</a>
Then, create a directive...
angular.module('myApp').directive('ngRemoveBirthday', ['myService', function(myService){
return function(scope, element, attrs){
angular.element(element.bind('click', function(){
myService.removeBirthday(scope.$eval(attrs.ngRemoveBirthday), scope);
};
};
}])
Then in your service...
angular.module('myApp').factory('myService', [function(){
return {
removeBirthday: function(birthdayIndex, scope){
scope.bdays.splice(birthdayIndex);
scope.$apply();
}
};
}]);
When you write your code properly like this, you will make it very easy to write future changes without having to restructure your code. It's organized properly, and you're handling custom click events correctly by binding using custom directives.
For instance, if your client says, "hey, now let's make it call the server and make bread, and then popup a modal." You will be able to easily just go to the service itself without having to add or change any of the HTML, and/or controller method code. If you had just the one line on the controller, you'd eventually need to use a service, for extending the functionality to the heavier lifting the client is asking for.
Also, if you need another 'Delete' button elsewhere, you now have a directive attribute ('ng-remove-birthday') you can easily assign to any element on the page. This now makes it modular and reusable. This will come in handy when dealing with the HEAVY web components paradigm of Angular 2.0. There IS no controller in 2.0. :)
Happy Developing!!!
Here is another answer. I hope it will help.
<a class="btn" ng-click="delete(item)">Delete</a>
$scope.delete(item){
var index = this.list.indexOf(item);
this.list.splice(index, 1);
}
array.splice(start)
array.splice(start, deleteCount)
array.splice(start, deleteCount, item1, item2, ...)
Full source is here
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
if you have ID or any specific field in your item, you can use filter(). its act like Where().
<a class="btn" ng-click="remove(item)">Delete</a>
in controller:
$scope.remove = function(item) {
$scope.bdays = $scope.bdays.filter(function (element) {
return element.ID!=item.ID
});
}
Pass the id that you want to remove from the array to the given function
from the controller( Function can be in the same controller but prefer
to keep it in a service)
function removeInfo(id) {
let item = bdays.filter(function(item) {
return bdays.id=== id;
})[0];
let index = bdays.indexOf(item);
data.device.splice(indexOfTabDetails, 1);
}
An inline simple way is just add bdays.splice($index, 1) in your delete button.
<ul ng-repeat="bday in bdays">
<li>
<span ng-hide="editing" ng-click="editing = true">{{bday.name}} | {{bday.date}}</span>
<form ng-show="editing" ng-submit="editing = false">
<label>Name:</label>
<input type="text" ng-model="bday.name" placeholder="Name" ng-required/>
<label>Date:</label>
<input type="date" ng-model="bday.date" placeholder="Date" ng-required/>
<br/>
<button class="btn" type="submit">Save</button>
<a class="btn" ng-click="bdays.splice($index, 1)">Delete</a>
</form>
</li>
</ul>
Here i have buttons like this
<button type="submit" name="submit_1" class="btn green" value="submit_1">Save & Add Another</button>
<button type="submit" name="submit_1" class="btn green" value="submit_2">Save & Exit</button>
in my controller i redirect pages on button click i cannot change name of buttons because i am using in update function to redirect with submit_1
now what should do i also can use id maybe for this but dont know how to use it
if(Input::get('submit_1')) {
return redirect()->route('data.create');
} elseif(Input::get('')) {
return redirect()->route('data.index');
}
Its always redirect to create page but i want if i click button2 which is Save & Exit it should be redirect to index page.
what should i do to to differentiate between buttons except changing name of buttons.. if any method with id please help me and guide to best
You need to compare the input with a value.
At the minute your basically just saying if('submit_1') (or 'submit_2') either will evaluate to being true, you're not actually checking the the value for submit_1 is actually 'submit_1'.
(I think the confusion comes from having the value of one of your buttons being the same as the name of your buttons )
Change your if condition to be:
if(Input::get('submit_1') == 'submit_1')
Hope this helps!
You should look for the value of the submit_1 button.
if(Input::get('submit_1') == "submit_1") {
return redirect()->route('data.create');
} else if(Input::get('submit_1') == "submit_2") {
return redirect()->route('data.index');
}
However giving same name to 2 different buttons is not a good approach.
first set id in your button.
lets say id 1 and id 2
In this case route call in your button should be like..
<a href="[your route]" id=1 class="btn green">
And in your routs it should be like
Route::get('[your link to be displayed]{id?}', 'Controller#action')
In th function call it should be like
public function action($id = null) {
if($id=1) {
return redirect()->route('data.create');
}
elseif($id=2) {
return redirect()->route('data.index');
}
}
Hope this would be usefull
I have seen this wiki where they populate a dropdownlist of cities, depending of the value of another dropdownlists that contains countries, using an ajax call with the update option. I need to implement something similar, but my dropdownlist depends on two dropdownlists:
<div class="row">
<?php echo CHtml::label('Countries', 'country_id'); ?>
<?php echo CHtml::dropdownlist('country_id', '',$countries); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'globaladmin'); ?>
<?php echo $form->dropDownList($model,'globaladmin',User::itemAlias('AdminStatus')); ?>
<?php echo $form->error($model,'globaladmin'); ?>
</div>
The user must select a country, and then only if in the second list "No" is selected, a new dropdown lists must be populated with the cities info (just like in the wiki example).
As I said it is similar to the example, but the new dropdown depends on 2 values (the id of the contry selected on the first list and if "No" is selected in the second one). How could I solve it?
EDIT: Explaining a little more
In the example, the country dropdown which contains the ajax call is like:
echo CHtml::dropDownList('country_id','', array(1=>'USA',2=>'France',3=>'Japan'),
array(
'ajax' => array(
'type'=>'POST', //request type
'url'=>CController::createUrl('currentController/dynamiccities'), //url to call.
'update'=>'#city_id', //selector to update
)));
I can't define such a ajax call in my country list, because I must wait the value of the second dropbox. Only if "No" is selected in this list, the ajax will be executed (and the city dropdownlist populated and showed). If "Yes" is selected then the city dropdownlist must be hidden.
Just add an ID to your globaladmin drop down and then do like below:
$("#THE ID YOU HAVE SET").on('change',function(){
// You can use $(this).val()
// and send it via an ajax request into your own url
var valueOfMyGlobalAdminDropDown=$(this).val();
if(valueOfMyGlobalAdminDropDown=="yes"){
//DO SOMETHING
}else{
//DO SOMETHING ELSE
}
});
it is also strongly recommended to use jquery live(in jquery version -1.7) or jquery ON(in jquery version +1.7) to keep your page alive in ajax requests.
When i select value from drop down list,
and I submit form, i want my drop down list to have selected value,
not to be on default value again.
I try like this, but not working:
<?php echo $form->dropDownList($model, 'code', $countriesIssuedList, array('name'=>'countriesIssued'), $select = array($_POST['countriesIssued']));?>
Also i would like to add a first value to be default, not from db, i want to do it in the code like this, array('empty'=>'--Select country--')
but not working.
Thanks
If you must change the name of your dropdownList you must manually set the value of code to $_POST['countriesIssued'] in your controller/view. As for the default, prompt is used to set this.
<?php if(!$model->code) $model->code=$_POST['countriesIssued'];?>
<?php echo $form->dropDownList($model, 'code', $countriesIssuedList, array(
'name'=>'countriesIssued','prompt'=>'--Select country--'
));?>
The second parameter (currently 'code') must be a key in this array: $countriesIssuedList
See for example here.
"Also i would like to add a first value to be default" ... perhaps you can use array_merge()?
Previously I've created a question where I was wondering how to set selected value for dependent dropdown. That was easy, man adviced me just set second parameter.
echo CHtml::dropDownList('OpenLessons[Building]', $buildingClassID, $buildingList,array(
'ajax' => array(
'type'=>'POST',
'url'=>CController::createUrl('ajax/floorList'),
'update'=>'#OpenLessons_Floor',
)));
echo CHtml::dropDownList('OpenLessons[Floor]',$model->Class_ID, array(),array(
'ajax' => array(
'type'=>'POST', //request type
'url'=>CController::createUrl('ajax/roomList'),
'update'=>'#OpenLessons_Class_ID',
)));
echo CHtml::dropDownList('OpenLessons[Class_ID]',$model->Class_ID, array());
where $buildingClassId is value of select. So that works fine for first select. But how can I set the same for dependent ones? When I look at it's code it looks like this:
<select name="OpenLessons[Floor]" id="OpenLessons_Floor">
</select>
I expected it to have some options, because I set default value for first one. So even if I put as second parameter of seconddropdown some value it wouln't be selected.
Any advices/suggestions?
UPDATE I'd mention that I don't see at XHR console call of floorlist. How can I make it?
UPDATE
$(document).ready(function()
{
$('#OpenLessons_Building').trigger('change');
$('#OpenLessons_Building option').trigger('click');
}).on('change','#OpenLessons_Building',function()
{
console.log('changed');
}).on('click','#OpenLessons_Building option',function()
{
console.log('clicked');
});
Tried like this. Both actions - change and click has happened because I can see output in console, but the dependent arrays are still empty.
You should use $("#OpenLessions_Building").on("change", function() { your code here });
The trigger function was actually does is execute the action (change or click in your case) of the dropdown as soon as the page loads.