I am using lodash _.filter function. While filtering, I want to remove an element if it same as its successive element. In this code, display
Here is the scenario,
fObj=[1,2,3]
template=[{"v":1,"d":"ABC","disabled":true},{"v":2,"d":"xyz","disabled":true},{"v":3,"d":"PQR","disabled":false},{"v":4,"d":"lmn","disabled":true}]
arr = _.filter( template, function ( item )
{
return item.disabled === true || fObj.indexOf( item.vm ) !== -1;
});
This is a kind of parent child, assume ABC,XYZ are parent. Parents which doesn;t have children has to be removed.
Since XYZ has a child PQR, i should display both. There is no relationship between parent and child.
We have to assume, when two successive elements have disabled=true, I want to remove both.
2 parents(abc and lmn) which doesn;t have child should be removed
I made an example for you
var arr = _.filter( template, function ( item, index )
{
if(item.needToBeRemoved) {
return false;
} else {
var isNotTheLastElement = index < (template.length - 1);
if(isNotTheLastElement) {
var nextItem = template[index+1];
if(item.disabled && nextItem.disabled) {
nextItem.needToBeRemoved = true;
return false
}
}
}
return true;
});
Here is the jsFiddle
Related
I'm in need of help with computed properties .. it's hard to explain but I'll try ..
I have a table with filter and pagination that I created.
When I pass the data directly from a request the API works,
but when I have to work with data coming from vuex I'm having trouble ...
Because I do not know when the data will be filled in vuex
And then I use the computed property because the moment the vuex is filled it will capture the data ..
However as the function that fills the data is the same one that is executed when I click on the page I crash the process and the page stops working.
Below is the computed property:
list(){
if (this.url_get == '' && this.$store.state.table.list.length > 0){
this.total_data = this.$store.state.table.list.length
this.repos = this.$store.state.table.list
this.getPaginatedItems(1)
}
var filter = this.configs.filter.toString().toLowerCase()
var items = ''
if (filter == ''){
items = this.dados
}else{
items = this.repos
}
const list = this.$lodash.orderBy(items, this.configs.orderBy, this.configs.order)
this.reverse = 1;
if (this.$lodash.isEmpty(filter)) {
return list;
}
var result = this.$lodash.filter(list, repo => {
return repo[this.filter_term].toString().toLowerCase().indexOf(filter) >= 0
})
return result
},
And the function:
getPaginatedItems(data) {
var items = this.repos
var page = data
var per_page = 10
var offset = (page - 1) * per_page
var max_item = offset+per_page
var paginatedItems = this.$lodash.slice(items, offset, max_item)
var obj = {
offset: offset,
current_page: page,
per_page: per_page,
total: items.length,
total_pages: Math.ceil(items.length / per_page),
data: paginatedItems,
last: offset+paginatedItems.length,
max_item: max_item
}
this.pagination = obj
this.dados = this.pagination.data
},
Request who fill the data in vuex
axios
.get(`api/getusuariosgrupo/${id}`)
.then(res => {
if (res.data.dados !== undefined && res.data.dados.length !== 0){
vmThis.isEditing = true
var d = {
list: res.data.dados,
length: res.data.dados.length
}
this.$store.commit('SET_TABLE', d)
}else{
vmThis.isEditing = false
}
vmThis.$bus.$emit('processando',{val: false})
})
I'm absolutely newbie in the Dojo, so my question may be too evident. Sorry.
I've programmatically created the complex menu, including MenuBar, based on the rows, selected from the DB.
All problems were solved besides one: the alignment of the final items and submenu items differ.How it looks like All submenus primarily were rendered in the same line. Only by adding the MenuSeparator I was able to divide them.
I'm lost I've found the example in the Internet, that shows exactly what I need (including the right-hand arrow for submenus) Example . I've used exactly the same algorithm to create menu. But I cannot get the same result.
Please, help.
I've noted that the image is not accessible.
In pure text it looks like:
Final 1
Final 2
Final 3
DropDown 1
DropDown 2
Indent depends on the submenu width.
Think, now I know what happened (don't know though, how to work around it).
The problem is the widget rendering.
The final menu option (leaf) is rendered as table row (tr and td tags).
The PopupMenuItem is rendered as div between rows.
Once more, I have no clue, how to avoid it.
Here is the code. A couple of notes:
1.The rows is the two dimensional array
2.The rows with ParentID=0 are the MenuBarItems
3.pM is the MenuBar widget
createMenu: function (rows, pM) {
var me = this; // for references from the event handlers, where 'this' means event origin (instead of lang.hitch)
// First define the indexes of the DB fields
var xMenu_Id;
var xMenu_Title;
var xParent;
var xURL;
var xUser_Roles;
var i;
for (i = 0; i < rows[0].length; i++) {
switch (rows[0][i]) {
case 'Menu_Id':
xMenu_Id = i;
break;
case 'Menu_Title':
xMenu_Title = i;
break;
case 'Parent':
xParent = i;
break;
case 'URL':
xURL = i;
break;
case 'User_Roles':
xUser_Roles = i;
break;
}
}
// Define the function to filter the menu rows
// Parameters: r - two-dimentional rows array
// p - criterion (the parent menu ID)
// idx - index of needed field
// f - returned filtered array (no need to use in calling statement)
var filterArray = function (r, p, idx, f) {
f = dojo.filter(r, function (item) {
return item[idx] == p;
});
return f;
}
// Define the recurcive function to create the sub menu tree for Menu bar item
// Parameters: parentMenu - the menu to add childs
// parentID - the ID of parent menu to select direct children
// role - current user role
var subMenuFactory = function (parentMenu, parentID, role) {
var i;
var fa = filterArray(rows, parentID, xParent);
var sub;
for (i = 0; i < fa.length; i++) {
if (fa[i][xUser_Roles].indexOf(role) >= 0 || fa[i][xUser_Roles] == 'all') {
if (fa[i][xURL] != '0') { // leaf
url = fa[i][xURL];
parentMenu.addChild(new MenuItem({
dir: 'ltr',
label: fa[i][xMenu_Title],
action: fa[i][xURL],
onClick: function () { me.menuAction(this.action); }
}));
}
else { // DropDown Node
sub = new DropDownMenu({ dir: 'ltr' });
subMenuFactory(sub, fa[i][xMenu_Id], role);
parentMenu.addChild(new MenuSeparator({}));
parentMenu.addChild(new PopupMenuBarItem({
dir: 'ltr',
label: fa[i][xMenu_Title],
popup: sub
}));
}
}
}
}
// Get array of Menu bar items
var filtered = filterArray(rows, 0, xParent);
var pSub;
var user_Role = this.user.Role;
for (i = 0; i < filtered.length; i++) {
if (filtered[i][xUser_Roles].indexOf(user_Role) >= 0 || filtered[i][xUser_Roles]=='all') {
if (filtered[i][xURL] != '0') // leaf
{
pM.addChild(new MenuBarItem({
dir: 'ltr',
label: filtered[i][xMenu_Title],
action: filtered[i][xURL],
onClick: function () { me.menuAction(this.action); }
}));
}
else { // DropDown Node
pSub = new DropDownMenu({ dir: 'ltr' });
subMenuFactory(pSub, filtered[i][xMenu_Id],user_Role);
pM.addChild(new PopupMenuBarItem({
dir: 'ltr',
label: filtered[i][xMenu_Title],
popup: pSub
}));
}
}
}
},
I've found what's the problem. In the required array of define I erroneously import PopupMenubarItem instead of PopupMenuItem. In the function the parameter is named right - PopupMenuItem, but evidently it couldn't help a lot...
Thanks to everyone who tried to help me.
Regards,
Gena
Validate if checkbox should be displayed in html page:
get canPerformCommand() {
let r = false;
let valids = ['Success', 'Error'];
if (this.requests.length == 0) return false;
if (valids.indexOf(this.myresult[0].requestStatus) > 0) {
r = true;
}
return r;
}
Html page:
<span if.bind="canPerformCommand" class="panel-heading-buttons">
<button click.trigger="confirm()">Confirm</button>
</span>
Search:
return this.myService.getRequests()
.then(data => {
this.requests = data
//Somehow refresh canPerformCommand here?
});
this.requests will be empty on first page load, resulting in canPerformCommand = false.
I want to refresh canPerformCommand when using the search function.
Currently canPerformCommand will not refresh itself after a search has been done.
How do I refresh canPerformCommand after search using Property Dependencies?
Solution:
The easiest and most logical solution would be to change canPerformCommand into two separate entities -- a flag variable and a function. Make the flag variable be canPerformCommand and keep the if.bind=canPerformCommand but change the name of your function to updateCanPerformCommand() so that you can easily call this function from your return this.myService.getRequests() .then function.
Details:
Set up your view-model like this:
export class App { // <-- (or whatever yours is called)
canPerformCommnad = false;
constructor() {
// ...
}
updateCanPerformCommand() {
let r = false;
let valids = ['Success', 'Error'];
if (this.requests.length == 0) {
this.canPerformCommand = false;
} else if (valids.indexOf(this.myresult[0].requestStatus) > 0) {
this.canPerformCommand = true;
}
}
}
I believe you need to change myresult to requests in the canPerformCommand getter:
get canPerformCommand() {
let r = false;
let valids = ['Success', 'Error'];
if (this.requests.length == 0) return false;
if (valids.indexOf(this.requests[0].requestStatus) > 0) {
r = true;
}
return r;
}
Since this getter will be dirty checked by Aurelia, it will be called every 200ms. To avoid that, you can add a computedFrom decorator:
import {computedFrom} from 'aurelia-framework';
export class MyClass {
....
#computedFrom('requests')
get canPerformCommand() { ....
I replaced:
if (valids.indexOf(this.myresult[0].requestStatus) > 0) {
r = true;
}
With
if (valids.includes(this.requests[0].requestStatus)) {
r = true;
}
And now it works. I was using the indexOf function on other pages aswell, and strangely enough it worked on most of them. Must have been something wrong in my model.
Also, I agree that it would be better to use computedFrom.
I have created a function for getting all links and clicking on them and then handle the windows using another method. Everything works fine, but now I want to put a condition that only few links are clicked. So the function is like:
this.getLinks = function(){
browser.driver.findElements(that.links).then(function(foundElements){
var val;
for(var i =0;i<foundElements.length;i++){
browser.sleep(3000);
foundElements[i].getText().then(function(textValue){
val = textValue;
**console.log(val);**
});
if(val != '??????' || val != '?????????' || val != '??????'){
foundElements[i].click();
that.getWindows();
}
}
});
};
I want to get the value of val out of promise so that I can put a condition that only selected links are clicked.
Use filter() to filter out elements based on the text value and each() to apply a function to each element of the filtered elements:
this.getLinks = function() {
element.all(that.links).filter(function(elm) {
return elm.getText().then(function (val) {
return val != '??????' || val != '?????????' || val != '??????';
});
}).each(function (elm) {
elm.click();
});
};
Hi I just want to populate the select or comboBox.
I am able to populate both with the searchAttr to any string from JSON. But not so when there are null values.
JSON string :
[{"batch":"0000001000"},{"batch":"0000"},{"batch":""},{"batch":null}]
dojo code:
var selBatch = new ComboBox //located at the left side of the page and it is the second select box in a row
(
{ id:'ID_selBatch',
value:'',
searchAttr:'batch',
placeHolder:'Select...',
style:{width:'150px'},
}, 'node_selBatch'
);
on(selTest, 'change', function(valueCard)
{
var selectedTest = this.get('displayedValue');
var selBatch = registry.byId('ID_selBatch');
console.debug('Connecting to gatherbatches.php ...');
request.post('gatherbatches.php',
{ data:{nameDB:registry.byId('ID_selPCBA').value, nameCard : valueCard},
handleAs: "json"}).then
(
function(response)
{
var memoStore2 = new Memory({data:response});
selBatch.set('store', memoStore2);
selBatch.set('value','');
console.debug('List of batches per Test is completed! Good OK! ');
},
function(error)
{
alert("Batch's Error:"+error);
console.debug('Problem: Listing batches per Test in select Test is BAD!');
}
);
selBatch.startup();
});
Error :
TypeError: _32[this.searchAttr] is null
defer() -> _WidgetBase.js (line 331)
_3() -> dojo.js (line 15)
_f.hitch(this,fcn)(); -> _WidgetBase.js (line 331)
Please advise though it might strange to have null values populate in the select box but these null values are related to data in other columns in database, so the null values included so that I can apply mysql scripts later. Or do you have other better suggestion?
Clement
You can create a QueryFilter as in this jsfiddle to achieve what you want, but it might be simpler to have two data items. Your original model with possibly null batch properties, and the model you pass to the store which is used by the ComboBox.
But anyway, this can work:
function createQueryFilter(originalQuery, filter) {
return function () {
var originalResults = originalQuery.apply(this, arguments);
var results = originalResults.filter(filter);
return QueryResults(results);
};
}
and
var memoStore = new Memory({
data: data
});
memoStore.query = createQueryFilter(memoStore.query, function (item) {
console.log(item);
return !!item.batch;
});
and the dummy data:
function createData1() {
var data = [];
for (var i = 0; i < 10; i++) {
data.push({
name: "" + i,
batch: (0 === i % 2) ? "batch" + i : null
});
}
return data;
}
Screenshot. The odd numbered batch items are null in my example.