AngularJS - Editing an object and applying / reverting changes - javascript

I have a table of items with an edit button next to it. When the edit button is clicked, the fields in that row turn into input fields where they can be edited, and a cancel button shows up. If they click cancel, the fields turn back into regular display fields. It's kind of like inline editing. I have two sets of <td> elements: one for display and one for editing.
What I'm looking for is a good way for me to keep the item's original values, so that when they click cancel, the data goes back to what it was originally. But if they click save, I'd like that data to stay on the object and that's what should be displayed.
I originally tried this (logic and processing is in the controller): On the edit button click, I'd create a "snapshot" of the object as an attribute on itself. Something like...
vm.edit = function(item) {
item.modified = angular.copy(item);
}
So what I'm actually doing is, when the row is not being edited, I'm displaying item.someProperty. When the edit button is clicked, it performs that copy in the controller, and the fields I show are actually item.modified.someProperty. Those are the different bindings in those two sets of <td> elements I mentioned, aside from the fact that the second set are input fields.
It works well as far as reverting goes (when they click cancel), but I'm stuck at the part where I want to update the object's original values if they click save. Basically, I need a way to get item.modified properties onto item itself. I've tried doing something like:
vm.save = function(item) {
item = angular.copy(item.modified);
}
And it doesn't seem to be working. I don't think I expected it to work in the first place, because it's kind of like overwriting itself with itself. Not sure if that would work.
What is a good way to accomplish this? Or maybe there's a better way to do what I'm trying to do?

Use a combination of copy() and extend(). Only edit the copy and store a reference to original that you can extend when you save
var storedItem;
// copy to variable before editing and store reference to original
vm.edit = function(item) {
storedItem = item;
vm.editItem = angular.copy(item);
}
vm.save = function() {
angular.extend(storedItem, editItem);
vm.editItem = null;
storedItem = null;
}
Set various ng-model to vm.editItem properties. If user cancels edit the original object has been unchanged so there is nothing to revert

Related

How does angularjs binding work when copying objects?

I have several html checkbox that is either on/off based on the properties of an object inside of an array say: objectArray.get(i).isCheckBoxActive. Since the user can change the object properties I'm trying to implement a button that reset all changes. My idea was creating a copy of objectArray (say objectArrayOriginal) and when the button is clicked it calls a function that copies back objectArrayOriginal into objectArray. I would expect that if a checkBox is off in objectArrayOriginal then, after pressing the button, it should be off also in the html page. To copy the object I did:
var objectArrayOriginal = JSON.stringify(objectArray)
.....
function clickReset(){
vm.objectArray = JSON.stringify(objectArrayOriginal)
}
I checked and although the field objectArray.get(i).isCheckBoxActive gets reset to its original value; the checkboxes remain checked/unchecked. The solution I found to be working is iterating over objectArray and comparing the values one by one with objectArrayOriginal. I would like to understand why the previous method fails and if there's a better one. Thanks in advance for any help!

Local Storage set to dropdown in Javascript

I'm been using this link. The issue is when I'm done submitting and filling those dropdown it reloads, When I come back again the previous value will gone. I just want to remain those value in dropdown but I think there is a conflict when using that link above. It also didn't display the other value of dropdown. All I know I should use localStorage. Is there any expert can give me directions and ideas for this?
Setting the value of dropdown when I click search/submit button
var values = document.getElementById('province').value;
localStorage.setItem("prov", values);
getting the value of province dropdown
document.getElementById("province").innerHTML = localStorage.getItem("prov");
It is possible to apply this through that link I provided?
Firstly, make an object that you can read from with mental ease.. something like
var obj={province:provinceElement.value, municipality:Municipality.value, ...etc}
then when you save all your values to the object, save it with a key("whatever it is once it's a key only your code uses")
localStorage.setItem("uniqueKeyOnlyMyCodeUses",JSON.stringify(obj))
Then you can get all your data like
var localObj=JSON.parse(localStorage.getItem("uniqueKeyOnlyMyCodeUses"))
localObj would have all the data you saved in just one key and objects are a very easy way to play around with the data you gave

Preserve dynamically changed select values when back button clicked

I have a form which filters through different cars, and it's working perfect.
When a user selects a "Make" the correct sibling "Models" are populated into the next dropdown, so on and so forth.
The problem is that once a user has performed a search, if they click the browser's back button, the select values which are dynamically populated - are back to default!
I am not using ajax to dynamically populate the select fields, but only javascript where I am reading a JSON file and updating the models/series/etc like that.
I have looked at this post: Preserve dynamically changed HTML on back button
And I do not understand how this works, I have also heard about localstorage - what would be the best avenue for me to travel down? Thanks.
Using localStorage for this can be a bit unwieldy (when and how should I clear this value?) and there are security related considerations that may make it an infeasible solution.
Another option is to use a hidden textbox which makes use of the browser's default behaviour.
When a page is loaded after clicking the back button, browsers appear to populate textboxes based on the value contained in it when the user left the page (even if that value was dynamically changed). Note, this is different to how hidden inputs are handled, where dynamic changes are ignored, so you must use a textbox.
<select></select>
<input type="text" style="display:none" />
<script>
// store the dropdown's value in a hidden textbox which is persisted and
// used to populate the dropdown when the back button is used to get here
$('select').on('change', function() {
$('input').val($(this).val());
});
// example showing dynamic population of dropdown
$.ajax({
url: 'api/get-dropdown-options',
success: function(data) {
// dynamically populate the dropdown
$('select').html(data);
// update the dropdown's value based on the persistent value
// retained in the hidden textbox
$('select').val($('input').val());
}
});
</script>
Because the data is dynamically loaded, the browser will not be able to repopulate the previously selected entries when the user goes back to the previous page.
I suggest you make use of the browser's localStorage to store the latest selections and retrieve them when the user goes back. To accomplish that it's as simple as setting a new variable to the localStorage object and later retrieving it like so:
localStorage.make = "BMW";
alert(localStorage.make);
Also here's a more useful example:
select = document.getElementById("make");
if (localStorage.make) {
select.options[localStorage.make].selected = true;
}

Trying to remove buttons on click, but they keep coming back (JavaScript, HTML)

I'm having this problem with buttons that I don't know how to solve. I have a table, and each row has a "Pack" action button. When it's clicked, the button is removed so that the user can't accidentally click it again and 'pack' the same item twice.
It has been working well so far, but I just noticed that when you click to the next page of the table (when it has more than 15 or so rows) and go back to the first page again, any buttons you clicked on that first page (and removed) are back.
No matter what pages you move to, I need my table to "remember" which rows' action buttons were clicked/removed. I have no idea how to do this, though.
Here is my code that removes the action button when you click:
// Pack action button
$(document).on('click', ".box-electrode", function (e) {
var id = $(this).attr('value');
var sn = $(this).data('sn');
addElectrodeToBox(id, sn);
$(this).remove();
});
The table itself is created using DataTables.
Can someone point me in the right direction?
Edit
Here is some code I've come up with based on the answer below, but it's not working. There are no errors in the JS console, it just doesn't seem to do anything.
$(document).on('page.dt', function () {
var $allSerialNumbers = $('.box-electrode');
$('#electrodes li').each(function (i, li) {
var $id = $(li).data('id');
for(var index = 0; index < $allSerialNumbers.length; index++){
if($id == $allSerialNumbers.eq(index).attr('data-id')){
$('.box-electrode').eq(index).remove();
}
}
})
});
$allSerialNumbers represents all the action buttons, and $('#electrodes') is the list I'm comparing to.
I think part of the problem (other than my clumsy JS skills) might be that DataTables' Page Change Event page.dt only seems to affect the page that is being changed, rather than the page being changed to. For example, when I'm on the 2nd page of my table and click back to the first page, my JS code is acting on the 2nd page instead of the 1st (which is what I need).
Create a JavaScript empty array;
DataTables library has page changing event;
When user presses the button - get button's value, store it in the array and remove the button;
When user changes the page - page's change event will be fired -> cleaning function will be executed, which will read the array, search needed buttons by value and remove them if exist.

jQuery searchable checkbox list and tristate checkbox

I'm building a simple asp page on which I have list of peoples with checkbox on left of every name.
I've managed to create a simple jQuery script that allows hiding and showing rows of table based on input:
http://jsfiddle.net/Tq97v/ (first part)
As You can see I can enter part of name and then specific row are hidden.
Using red "x" I can uncheck all checkboxes.
What I'm trying to do now is to change that static red "x" into tristate checkbox.
Don't have idea how to even start.
Do I must add change listener to every checkbox in my list?
Second thing - how to create multiple instances of the same "plugin" on site.
Right now I'm identifying input by it, but it would be nice to call function with that input as param, and it would fine table after that input and create necessary logic.
This way I could call function multiple times on page to have more than one list.
I'm not asking for whole solution (of course it is always welcome :) ) but what I need is idea how to accomplish this in efficient way and as optimized as possible, because sometimes my list has 500+ elements.
P.S. don't look at HTML code, it is ASP generated.
I found this plugin: https://github.com/bcollins/jquery.tristate, but I have no idea how to use it with my list.
UPDATE:
I've managed to turn my code into functions, but right now I must call 3 functions for every list.
Here is my updated code: http://jsfiddle.net/65MEV/4/
How can I change it to one function? Will it be better?
This is my updated code. Still thinking about way of doing that Indeterminate Checkbox instead of my remove image.
UPDATE2
I build working code :)
http://jsfiddle.net/65MEV/9/
But I would like to improve it as much as possible.
Any suggestions are welcome!
A tristate checkbox is like the Three-Portal Device: an illusion.
What you actually want is to make the checkbox indeterminate (by setting the property of the same name to true). To implement this, you will need a change (or click) handler on each checkbox, then you'll need to check if all of them are in the same state, and if not then you set the indeterminate property. It's a hassle, really, because you rarely see indeterminate checkboxes and so most users don't know what to do with them. To be avoided, if possible.
To create multiple instances of the same plugin access elements relatively to an other element.
For example: in your case instead of keeping the item in a jQuery object var $tableRows = $('table.myList tr'); access them in the event.
$('#user_name').keyup(function () {
var sValue = $.trim($('input#user_name').val());
if(lastInput==sValue) return;
var $tableRows = $(this).next().next().find("table.myList tr");
if (sValue == '') {
$tableRows.show();
} else {
$tableRows.each(function () {
var oLabel = $(this).find('label');
if (oLabel.length > 0) {
if (oLabel.text().toLowerCase().indexOf(sValue.toLowerCase()) >= 0) {
$(this).show();
} else {
$(this).hide();
}
}
});
lastInput=sValue;
}
});
and you only have your actual list.
And for the tree state checkbox you don t need a plugin just add a button or link and every click check it status you can keep the status by jQuery data and change the element image according to this data.

Categories