How to delete single field from the table in angularjs [duplicate] - php

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>

Related

How display the form multiple times below one another by clicking a button in Vue.js

I want to display a form multiple times by clicking a button in vuejs, how is it possible?
is it possible to read number in a column from the database and display a form based on that number, for example if i want to register garage and also number of cars in that garage, by reading the number of cars in the garage table , i want to display number of forms based on that cars.
if it is two cars in the garage, then two forms will be displayed and so on.
There are tons of ways to do it, and the representation is delivered via v-for.
Specifics depend on what you want to show in form, are there loaded values, how do you want to save them etc.
In this example i get some variable form backend (it can also just be 0, as is the default value), and add a form item object for the received amount or whenever you press the button to the array that is iterated through. If you use Vue.set or =, Vue will notice difference and rerender the component with the changed v-for loop. (it doesn't notice, for example, push)
Then you would just submit and/or validate formValues
Alternatively you could also do something similar to v-for="number in range(0, 4)" and track the form values somehow else. Either way, world is your oyster.
<template>
<div>
<div v-for="(form, index) in formValues" v-key="index">
<form>
<input v-model="formValues[index].yourFormVariable">
<input v-model="formValues[index].yourOtherFormVariable">
</form>
<div>
<button #click="addCar()">
</div>
</template>
<script>
...
data () {
return {
formValues: [],
carAmount : 0,
}
},
...
methods () {
getCarAmount () {
/*however you want to get your variable from wherever, should launch it on computed or whenever you want to reset the value*/
this.carAmount = response.data.carAmount // carAmount being the db variable
for(let i = 0; i < this.carAmount; i++){
this.addCar()
}
},
addCar () {
this.formValues[this.carAmount] =
{
yourFormVariable: '',
yourOtherFormVariable: '',
};
this.carAmount++;
}
},
</script>

Hide the all other divs except one which is clicked

I have list of user and their dates in PHP and onclick of specific user, I want to hide div other than one whose link is clicked
For example :
<div class='person' id='add_new_date_8' style='display:none;'>
<div class='person' id='add_new_date_9' style='display:none;'>
<div class='person' id='add_new_date_10' style='display:none;'>
<a href='javascript:void(0)' onclick="addMydate('<?PHP echo $id;?>')">Add a new Date?<a/>
So if $id = 8 then hide all div of class person which has id other than 'add_new_date_8'
Make it simple in jquery
$(document).on('click', '.person', function() {
$('.person').hide();
$(this).show();
});
access id in js function. and first hide all the div with person class and then show the which have matching id.
function addMydate(id){
$('.person').hide();
$('#add_new_date_'+id).show();
}
The other solutions so far will work, however I prefer to use .siblings()
function addMydate(id){
var selectedEl = $('#add_new_date'+id);
selectedEl.siblings().hide(); //siblings() takes all other elements of the same parent
selectedEl.show();
}
This will prevent the element itself from being hidden and then shown again, and might save you some headaches on animations, should you add those.
note: this depends on your HTML structure instead of classes, which is a bit less flexible. You can also use the following to exclude the element you want to show from the elements that get hidden:
$('.person').not('#add_new_date'+id).hide()
You can use siblings to get the siblings of the clicked element.
$(document).on('click', '.person', function() {
$(this).show().siblings('.person').hide();
});
Get the siblings of each element in the set of matched elements, optionally filtered by a selector.
Docs: http://api.jquery.com/siblings
EDIT
function addMydate(userId) {
$('#add_new_date_' + userId).show().siblings('.person').hide();
}

dropdown menu with links to the functions

I currently have two buttons. 1 to change a mysql variable to 1 and one to change it to 0
This works fine but i would like to have them in a dropdown. So i dont have 2 buttons showing.
<td>
<i class="fa fa-check"></i>
<i class="fa fa-check"></i>
</td>
the first one sets "complete" to 1 and the second one sets "complete" to 0.
Prepare options array as below
$opts=array(
'' =>'--Select--',
'0'=>'Option 1',
'1'=>'Option 2'
);
Generate dropdown with below CI Code:
<?php echo form_dropdown('dropdown_name',$opts,'','onchange="gotopage(this.value)"');?>
In js:
function gotopage(val)
{
if(val!="")
{
window.location = "<?php echo site_url("PATH_TO_GO");?>/"+val; // pass parameter in url
}
}
Without seeing the code only we can tell you in general what to do to make a drop down in codeignitor. In your view page, you should put this to generate a select combination box. The value can be received only if, its in a form. if you don't want a form, then you may need to incorporate Ajax with this.
<?php echo form_dropdown('cmb',$select_options,'0');?>
The first variable will become the name of the variable and the third variable is the default option that that has to be select (in this case Option 1 will be selected). The third variable is the data array which contains the options of the dropdown.
The data array, have to be like this, which have to be passed from controller into the view.
$select_options=array(
'0'=>'Option 1';
'1'=>'Option 2'
);

How to add extra parameter in zend paging

How i can add extra parameter in the zend paging.I have to provide filter functionality in the listing user. so i want to send search keywords with page numbers.
Paging code
$page = $this->_getParam('page', 1);
$paginator = Zend_Paginator::factory($data);
$paginator->setItemCountPerPage(2);//PAGING_RESULT_PER_PAGE
$paginator->setCurrentPageNumber($page);
$paginator->setPageRange(PAGING_PAGES_RANGE_PER_PAGE);
$this->view->users = $paginator;
I want to add search data onchange event to the paging .
This paging is working using ajax now what i want to it should be changed as per the filter data. I am not able to perform this....can you please provlde me any suggestion please
You can change the code from the javascript.
<script>
$(document).ready(function(){
$('.paginationControl a').click(function(){
if($('#keyword').val() != '')
{
var href = $(this).attr('href')+'/keyword/'+$('#keyword').val();
$(this).attr('href', href);
}
});
});
</script>
<input type="text" name="keyword" value="" id="keyword"/>
<div class="paginationControl">
2
3
4
5
</div>
I'm not quite sure what you mean with "extra parameter in the zend paging" ... are you trying to pass a GET-Parameter to an controller which has an paginator? What is inside $data? How does your search parameter and your route look like? You might try the following inside your bootstrap.php (if passing a get var is what you're struggling with):
protected function _initConstants()
{
[...]
defined('QSA_SEARCH') || define('QSA_SEARCH', 'q');
[...]
}
And inside your controller you can access it via:
[...]
$search = $this->getRequest()->getParam(QSA_SEARCH);
[...]
Passing a search string via get request:
http://domain.com/<controller>/<pagenum>?q=<searchstring>
e.g.:
http://domain.com/users/2?q=foo
EDIT:
Or are you having problems passing the search string towards Zend_Paginator::factory?

Joomla PHP: Checkbox won't uncheck

Making a simple component. If I save a new record with the box checked, it saves fine. If I go back and uncheck a previously checked item it reverts back to checked. I thought it had something to do with a hidden field, played with putting one of those in manually but that didn't fix it either so took it out.
Here's where I'm at:
An xml snippet:
<fieldset name="checks">
<field name="checkbox1"
type="checkbox"
label="First Checkbox"
value="1"
filter="intval"
/>
<field name="checkbox2"
type="checkbox"
label="Second Checkbox"
value="1"
filter="intval"
/>
...
</fieldset>
The edit.php file:
<div class="width-45 fltlft">
<fieldset class="adminform">
<legend>Checkboxes</legend>
<ul class="adminformlist">
<?php foreach ($this->form->getFieldset('checks') as $field): ?>
<li>
<?php echo $field->label; ?>
<?php echo $field->input; ?>
</li>
<?php endforeach ?>
</ul>
</fieldset>
</div>
Also added this towards the end before the form.token:
<input type="hidden" name="task" id="task" value="completion.edit" />
I tried deleting the value="1" in the xml but then I had the opposite problem where the check wouldn't save at all.
Any ideas?
Thanks!
=============================
Edit:
Model:
<?php
defined( '_JEXEC' ) or die;
jimport('joomla.application.component.modeladmin');
class AssessModelCompletion extends JModelAdmin
{
//tells it what kind of record and the prefix
public function getTable($type = 'Completion', $prefix = 'AssessTable', $config = array())
{
return JTable::getInstance($type, $prefix, $config);
}
//Load the data into the edit form
protected function loadFormData()
{
$data = JFactory::getApplication()->getUserState('com_assess.edit.completion.data', array()); //first try to get the data from the session, not db
if (empty($data)) {
$data = $this->getItem(); //this gets the data
}
return $data;
}
//Stores data in a session in case a field is missed
public function getForm($data = array(), $loadData = true)
{
$form = $this->loadForm('com_assess.completion', 'completion', array('control' => 'jform', 'load_data' => $loadData));
return $form;
}
}
And table:
<?php
defined ( '_JEXEC' ) or die;
class AssessTableCompletion extends JTable
{
public function __construct(&$db)
{
parent::__construct('#__tablename_completions', 'completion_id', $db);
}
}
======================================
References:
https://stackoverflow.com/questions/6964333/joomla-1-6-admin-form-processing-grouped-checkboxes-in-form
Tutorial code is not working any more in Joomla 2.5
http://docs.joomla.org/Developing_a_Model-View-Controller_%28MVC%29_Component_for_Joomla!1.7_-_Part_09#Adding_a_toolbar
So this is a kind of odd situation in that the documentation you list makes it seem that you would have to write no code to handle the checkbox (because as you point out a checkbox is different then checkboxes). But this does not seem to be the case because of the way that html checkboxes are submitted.
A quick overview of this issue and one solution can be found here: http://planetozh.com/blog/2008/09/posting-unchecked-checkboxes-in-html-forms/.
To use this, you would need to get the field's name out of the $field variable (which I'm not sure if it will be easy to access) and then place the <input type=hidden name='name' value=0> before <?php echo $field->input; ?>.
The other method to fix this would be to process the form data during save and override elements. Joomla has a prepareTable function that you could add to your model to edit data as necessary during save. The following example assumes that your form elements are wrapped in a jform array. (Confirm this by looking at the name fields in the html generated and they should be 'jform[checkbox1]')
protected function prepareTable(&$table)
{
$jform = JRequest::getVar('jform'); // load all submitted data
if (!isset($jform['checkbox1'])) { // see if the checkbox has been submitted
$table->checkbox1 = 0; // if it has not been submitted, mark the field unchecked
}
if (!isset($jform['checkbox2'])) { // likewise for other checkboxes
$table->checkbox2 = 0;
}
}
In this case, you would want to keep "value=1" in your xml fields file.
The problem ultimately is that Joomla loads the current data from the database during saving and then binds the posted data over the top of it. Because an unchecked box is not submitted in the post data, it does not overwrite the databases information and is thus not saved.
Although the documentation states that you do not have to do any manual handeling of the checkbox this is not true.
As no value is sent in the $_POST array when a checkbox is not checked the value is not overwritten and thus not saved which makes it impossible to uncheck the checkbox. To fix this you have to write special handling for your checkboxes in your table bind() function like this:
class YourcomponentTableYourview extends JTable
{
/**
* Constructor
*
* #param JDatabase A database connector object
*/
public function __construct(&$db)
{
parent::__construct('#__your_table_name', 'id', $db);
}
public function bind($array, $ignore = '')
{
if (!isset($array['name_of_field']))
$array['name_of_field'] = 0 ;
return parent::bind($array, $ignore);
}
}
As you don't have any model/table code showing, I think you may be mistaking JForm's purpose - it is purely for rendering of the form. You still have to have in your model/table something to handle the array that is returned for multivalued fields.
As Sam Moffat put it:
there is no coupling between the form definitions used to render the data and the models and table structures used to persist them
So I had a lot of fields and wanted to simply loop through them in my edit.php field to keep it clean. While all the answers offered were right they weren't easy to implement - got really messy really quickly, had trouble getting it to work, or couldn't figure out a cleaner way around it. I chewed on this for awhile and then today came across what is basically a field override.
The key:
The standard form field types are located in
joomla/libraries/joomla/form/fields/. You should not store custom
fields there, nor should you have to use this path in your own code,
but the standard types are usually good examples.
The custom field types that belong to your component are usually
located in administrator/components//models/fields. You can specify this or another path in your
code
So, I copied checkbox.php to models/fields. Then, towards the end of the file I added the empty field before the checkbox tag:
<input type="hidden" name="'.$this->name.'" id="'.$this->id.'" value="0" /><input type="checkbox" .....
Now, whenever I need a checkbox the empty field is also written. May not be the most efficient solution but simple to implement and can hopefully help someone else.
[Edit]
As a note, with every Joomla update you would probably need to compare the versions in the core in case there was a change.
I know this is an old question, but the official answer is long winded and I think I have a better solution.
Try setting the default value for the checkbox to 0 rather than 1 in your xml like so:
<fieldset name="checks">
<field name="checkbox1"
type="checkbox"
label="First Checkbox"
value="0"
filter="intval"
/>
<field name="checkbox2"
type="checkbox"
label="Second Checkbox"
value="0"
filter="intval"
/>
...
</fieldset>
I just came across your question and tried setting it to 0 as I didn't want to tamper with the core and hey presto it works.
My guess is that Joomla sees no value and thus sets the default instead.

Categories