I have the object words and a checkbox which should hide a specific element from this object, but I cannot get it work.
<body ng-controller="ArrController">
<input type="checkbox" ng-model="hide"> {{kc}}
{{words}}
</body>
The ArrController:
app.controller('ArrController', function ($scope, $http) {
$scope.hide = false;
$http.get('array.json').success(function(data) {
var keyword = 'lol';
$scope.words = data.unsorted_arr;
$scope.$watch('hide', function () {
if ($scope.hide == true) {
var remove = function() {
$scope.words.splice(keyword, 1);
}
$scope.kc = 'hidden';
} else {
$scope.kc = 'not hidden';
$scope.words = data.unsorted_arr;
}
});
});
});
The file array.json contains data for words:
{"unsorted_arr":{"gonna":3,"lol":114,"wouldn":2,"know":6,"lowkey":2,"man":5}}
The kc modifies according to the checkbox status, but the words stays the same.
Where am I wrong?
Splice is for removing something in an array, and it takes in two integers as parameters.
Since you have an object, just use delete:
delete $scope.words[keyword];
By doing, $scope.words = data.unsorted_arr, the two variables refer to the same object so deleting something from $scope.words will delete it from data.unsorted_arr.
Keep a reference to it so you can repopulate it later:
var word = $scope.words[keyword];
...
delete $scope.words[keyword];
...
$scope.words[keyword] = word;
You are confusing Indexed arrays with associative arrays,
Array.splice is a method of Indexed Arrays,
you have a simple Javascript Object (associative array)...
on POJO you can use the delete operator or a simply reassignment to undefined:
var a = { foo: 'baz' };
delete a['foo'];
var b = ['foo', 'baz'];
b.splice(0, 1)
In your example you are defining a function for removing the element, but the function is never being called.
var remove = function() {
$scope.words.splice(keyword, 1);
}
you may need to your logic to remove the function (as it doesn't seem to be needed) and replace the of use splice with the delete statement:
$http.get('array.json').success(function(data) {
var keyword = 'lol';
$scope.words = data.unsorted_arr;
$scope.$watch('hide', function () {
if ($scope.hide == true) {
delete $scope.words[keyword];
$scope.kc = 'hidden';
} else {
$scope.kc = 'not hidden';
$scope.words = data.unsorted_arr;
}
});
});
Related
For the code below, I wanted to make the _formsOk function work for both Javascript arrays and "JQuery objects". In function1(), I tried to create a Javascript array with all DOM elements except those that have a parent element with id="objectTypesContainer". Basically, function1() filters out the DOM elements I don't want before calling _formsOk() function, which does the actual form validation.
function1() {
var allForms = $('form:not(.vv_hidden)', this.selectMarketsContainer);
var nonObjectTypeForms = [];
allForms.each(function () {
if ($(this).parent().attr("id") !== "objectTypesContainer"){
nonObjectTypeForms.push($(this)[0]);
}
});
return this._formsOk(nonObjectTypeForms);
},
_formsOk: function($forms) {
var formOk = true;
console.log(typeof $forms)
$forms.each(function () { // This line fails
var validator = $(this).validate(DEFAULT_VALIDATION_OPTIONS);
if (!(validator && validator.form())) {
formOk = false;
}
});
return formOk;
},
However, I realized that because nonObjectTypeForms is now a JS Array rather than a "JQuery Object", the line marked (// This line fails) now fails.
The original code looked like this:
function1() {
var allForms = $('form:not(.vv_hidden)', this.selectMarketsContainer); // This is a "JQuery object", so no error occurs
return this._formsOk(allForms);
},
_formsOk: function($forms) {
var formOk = true;
console.log(typeof $forms)
$forms.each(function () { // This line fails
var validator = $(this).validate(DEFAULT_VALIDATION_OPTIONS);
if (!(validator && validator.form())) {
formOk = false;
}
});
return formOk;
},
Is there a way I can convert a JS array into a JQuery object ? I don't want to change _formsOk function definition just yet.
Instead of putting all elements in a new array, just use .filter() from the jQuery object.
allForms.filter(function () {
return $(this).parent().attr("id") !== "objectTypesContainer")
});
This will remove all the items you don't need in your selection and now allForms will only have the wanted elements.
Thanks in advance for any responses:
I don't think this is a duplicate: I reviewed that article in the first comment, that is just a general breakdown of objects and using "this" within javascript.
My other this.function's perform just fine, so I at least have the basics of JS Obj's figured out.
This issue is related to using .map() with a this.function within a constructed object.
The following Google Appscript code uses .map() to update a string in a 2d array. [[string, int],[string, int]]
For some reason, when using .map() it is am unable to access the function "this.removeLeadingZero". If that same function is placed outside of the OBJ it can be called and everything works just fine. For some reason the system claims row[0] is an [object, Object] but when I typeof(row[0]) it returns "string" as it should.
Error: TypeError: Cannot find function removeLeadingZero in object [object Object]. (line 106, file "DEEP UPC MATCH")
Is there any issue using this.function's with .map() inside an object or am I using an incorrect syntax?
function test2DMapping(){
var tool = new WorkingMappingExample()
var boot = tool.arrayBuild();
Logger.log(boot)
}
function WorkingMappingExample(){
this.arr= [["01234", 100],["401234", 101],["012340", 13],["01234", 0422141],["01234", 2],["12340",3],["01234", 1],["01234", 2],["12340",3],["01234", 1],["01234", 2],["12340",3],["01234", 1],["01234", 2],["12340",3]];
//mapping appears faster that normal iterations
this.arrayBuild = function(){
var newArray1 =
this.arr.map( function( row ) {
**var mUPC = removeLeadingZero2(row[0])** //working
**var mUPC = this.removeLeadingZero(row[0])** // not working
var index = row[1]
Logger.log(mUPC + " " + index)
row = [mUPC, index]
return row
} )
return newArray1;
};
}; //end of OBJ
//THE NEXT 2 FUNCTIONS ARE WORKING OUTSIDE OF THE OBJECT
function removeLeadingZero2(upc){
try {
if (typeof(upc[0]) == "string"){
return upc.replace(/^0+/, '')
} else {
var stringer = upc.toString();
return stringer.replace(/^0+/, '')
}
} catch (err) {
Logger.log(err);
return upc;
}
}
function trimFirstTwoLastOne (upc) {
try {
return upc.substring(2, upc.length - 1); //takes off the first 2 #'s off and the last 1 #'s
} catch (err) {
Logger.log(err);
return upc;
}
}
Inside the function that you pass to map, this doesn't refer to what you think it does. The mapping function has its own this, which refers to window, normally:
var newArray1 = this.arr.map(function(row) {
// this === window
var mUPC = this.removeLeadingZero(row[0]);
var index = row[1];
Logger.log(mUPC + " " + index);
return [mUPC, index];
});
You have four options:
Array#map takes a thisArg which you can use to tell map what the this object in the function should be:
var newArray1 = this.arr.map(function(row) {
// this === (outer this)
var mUPC = this.removeLeadingZero(row[0]);
// ...
}, this); // pass a thisArg
Manually bind the function:
var newArray1 = this.arr.map(function(row) {
// this === (outer this)
var mUPC = this.removeLeadingZero(row[0]);
// ...
}.bind(this)); // bind the function to this
Store a reference to the outer this:
var self = this;
var newArray1 = this.arr.map(function(row) {
// self === (outer this)
var mUPC = self.removeLeadingZero(row[0]);
// ...
});
Use an arrow function:
var newArray1 = this.arr.map(row => {
// this === (outer this)
var mUPC = this.removeLeadingZero(row[0]);
// ...
});
Additionally, you could stop using this and new.
I have solved this issue and below is the answer in case anyone else runs into this:
this needs to be placed into a variable:
var _this = this;
and then you can call it within the object:
var mUPC = _this.removeLeadingZero(row[0])
Javascript scope strikes again!
I have this block of code when user do delete or undelete it will update deleted property on model. my problem I'm using for angular.forEach() just want to see if it possible to change angular.forEach to use $scope.$watchCollection() ?
$scope.deleteForm = function (form) {
var result = confirm('Want to delete the form ?');
if (result){
var splitDeleteHref = form.deleteHref.split('/');
var formName = splitDeleteHref[1];
var formId = splitDeleteHref[2];
homeService.deleteForm(formName, formId);
$scope.$watchCollection('forms',)
//angular.forEach($scope.forms, function(value, key) {
// if (value.recordId === form.recordId) {
// $scope.forms[key].deleted = true;
// }
//});
}
};
$scope.undeleteForm = function (form) {
var result = confirm('Want to undelete the form ?');
if (result) {
homeService.undeleteForm(form).then(function () {
//angular.forEach($scope.forms, function (value, key) {
// if (value.recordId === form.recordId) {
// $scope.forms[key].deleted = false;
// }
//});
});
}
};
$scope.$watch and .$watchCollection are for watching for changes to an object or a collection of objects. These methods cannot be used to iterate over an array, which is what angular.forEach is for. Your usage of .forEach appears to be correct, so I recommend leaving it as is.
I have problem with below code. I have prices factory which returns object containing prices received from server by websocket. Prices are sent after button Create is clicked. Problem is that main.prices variable is not updated at all. I can check everything by Check button, which confirms this. Prices.data is updated, but this.prices is not, but it refers the same object, so I thought it should be updated as well. Do you have any ideas why below does not work as expected?
angular.module('myApp', ['ngWebSocket'])
.factory('ws', ['$websocket', function($websocket){
var url = 'ws://localhost/websocket';
var ws = $websocket(url);
return ws;
}])
.factory('prices', ['ws', function(ws){
var prices = {
data: [],
clear: function(){
this.data = [];
},
create: function(){
ws.send('send')
}
}
ws.onMessage(function(message){
message = JSON.parse(message.data);
var type = message.type;
if (type == 'new prices'){
prices.data = message.data;
}
});
return prices;
}])
.controller('main', ['prices', function(prices){
this.prices = prices.data;
this.check = function(){
console.log('works ', prices.data);
console.log('not works ', this.prices);
};
this.create = function(){
prices.create();
};
this.stop = function(){
prices.clear();
};
}]);
<div ng-controller="main as main">
{{ main.prices }}
<button ng-click="main.create()">Create</button>
<button ng-click="main.stop()">Stop</button>
<button ng-click="main.check()">Check</button>
</div>
There are a lot of issues with the code you posted (working on a fiddle so i can help rework it) ...
First change :
if (type == 'new prices'){
prices.data = message.data;
}
To:
if (type == 'new prices'){
prices.data.length = 0;
prices.data.push.apply(prices.data,message.data) ;//copy all items to the array.
}
From a readability / maintainability point of view you should just use this.prices vs this.prices.data. It's confusing to map them to other variables, when you can just use prices. Also note that I updated it to use "that" constantly to avoid any type of context this issues.
.controller('main', ['prices', function(prices){
var that = this;
that.prices = prices;
that.check = check;
that.create = create;
that.stop = stop;
function check(){
console.log('works ', that.prices.data);
console.log('not works ', that.prices);
}
function create(){
that.prices.create();
}
function stop(){
that.prices.clear();
}
}]);
To add to the previous response, you also have an issue on the clear():
var prices = {
...
clear: function(){
this.data = [];
},
...
}
when you do the clear with this.data = [] you are actually creating a new empty array an storing that in the this.data prop, and since this is a NEW array, the reference on main controller -> this.prices = prices.data; is still pointing to the old one. If you need to delete elements on the array just use this.data.length = 0 as Nix pointed out for the other method. that will keep all references in sync since you are re using the original array
I want to go through a JSON, if a certain condition applies then push some extra elements in that index.
I have this JS code:
$scope.addRoleToUser = function() {
var userid = $scope.selectedUser;
var tmpdata = [];
var index = 0;
//alert(userid);
angular.forEach($scope.users, function(data) {
if (data.id == $scope.selectedUser) {
tmpdata.push(data,{"roles":[{"id":"00","name":"newrole"}]});
}
else {
tmpdata.push(data);
}
index++;
});
$scope.users = tmpdata;
};
This is my initial JSON element:
$scope.users = [
{"id":"0","name":"User1","roles":[{}]},
{"id":"1","name":"User2","roles":[{}]},
]
I'm trying to get it to look like this after the function runs:
$scope.users = [
{"id":"0","name":"User1","roles":[{"id":"00","name":"newrole"}]},
{"id":"1","name":"User2","roles":[{}]},
]
But instead I'm getting this:
[{"id":"0","name":"User1","roles":[{}]},{"roles":[{"id":"00","name":"newrole"}]},{"id":"1","name":"User2","roles":[{}]}]
Just replace this inside your function
if (data.id == $scope.selectedUser) {
data.roles = [{"id":"00","name":"newrole"}];
}
Or, if you know that roles is not empty, you can do:
if (data.id == $scope.selectedUser) {
data.roles.push({"id":"00","name":"newrole"});
}
And after this line you can add your data to tmpdata!
That snippet now will look like this:
if (data.id == $scope.selectedUser) {
data.roles = [{"id":"00","name":"newrole"}]}); //or the other one
}
tmpdata.push(data);
Inside the forEach() callback you're just working with objects and as such, you can modify them directly inside the callback:
angular.forEach($scope.users, function(data) {
if (data.id == $scope.selectedUser) {
data.roles = [{"id":"00","name":"newrole"}];
}
});
Similarly you could modify almost anything of each entry by manipulating the respective data object.
Example Fiddle
The Array.prototype.push method is variadic: (https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/push).
When you call tmpdata.push(a,b,c), you are in essence appending the array [a,b,c] to tmpdata.
You can also decompose the problem with something like:
$scope.addRoleToUser = function() {
var thisUserid = $scope.selectedUser;
function addRolesFor(user) {
if (user.id === thisUserId){ user.roles = [{"id":"00","name":"newrole"}] };
return user;
}
retrun $scope.users.map(addRoles);
}
Please use the map function that is appropriate for your environment (like _.map), because the Array.prototype.map method is not supported by all browsers.