I'm using two variables with the same value. Variable A is an initial variable and variable B is the one that I use to apply changes, so when I want to reset variable B I just assign A to it, the problem is each time I do it, the changes of B then applied to both. I have look in many places and these are the solutions I tried:
List.toList()
_fields!.clear();
_fields = _initFields!.toList();
Spread operator (...)
_fields!.clear();
_fields = [...?_initFields];
Also tried the ones below from this post: Dart/Flutter – How to clone/copy a list
var newNumbers = List.from(numbers);
var newNumbers = List.generate(numbers.length, (index) => numbers[index]);
var newNumbers = List.of(numbers);
var newNumbers = List.unmodifiable(numbers);
Here the complete code:
import 'package:project/utilities/classes/filter_field.dart';
class FilterLogic {
List<FilterField>? _initFields = [];
List<FilterField>? _fields = [];
bool? listComplete = false;
void addField(FilterField? field) {
_fields!.add(field!);
}
void addInitField(FilterField? field) {
_initFields!.add(field!);
}
List<FilterField>? getFields() {
return _fields;
}
void resetFieldsToOriginal() {
_fields!.clear();
_fields = [...?_initFields!];
}
void showFields() {
print('_fields --------------------------------------------------------------------------------------');
_fields!.forEach((element) {
if(element.checked == true) {
print({ element.checked, element.field, element.filteredApplied, element.criteria, element.filteringOperators});
}
});
print('_initFields --------------------------------------------------------------------------------------');
_initFields!.forEach((element) {
if(element.checked == true) {
print({ element.checked, element.field, element.filteredApplied, element.criteria, element.filteringOperators});
}
});
}
}
Here is how I fill both variables:
filterCol.forEach((column) {
String? filteredApplied;
String? filteredCriteria = 'None';
bool checked = false;
filtersList.forEach((element) {
if (column.field == element.field) {
filteredApplied = element.operator;
filteredCriteria = element.criteria;
checked = true;
}
});
FilterField field = FilterField(
filteredApplied: filteredApplied,
field: column.field,
label: column.label,
filteringOperators: column.filteringOperators,
criteria: filteredCriteria,
checked: checked == true ? true : false,
);
FilterField initField = FilterField(
filteredApplied: filteredApplied,
field: column.field,
label: column.label,
filteringOperators: column.filteringOperators,
criteria: filteredCriteria,
checked: checked == true ? true : false,
);
setState(() {
filterLogic.addField(field);
filterLogic.addInitField(initField);
});
});
Here where I call the reset method:
DialogButton(
width: 106.25,
child: Text(
"CANCEL",
style: TextStyle(
color: Colors.white, fontSize: 14, fontFamily: 'Chivo'),
),
onPressed: () => {
Navigator.of(context).pop(),
setState(() {
filterLogic.resetFieldsToOriginal(); // <-------------
})
},
color: Color.fromRGBO(84, 84, 84, 1),
radius: BorderRadius.circular(0.0),
),
It's not enough just to copy the list cause your new list has references to the same FilterField instances. That means if you change any FilterField in the new list the same changes would be in the old one. So in your case, you need to make a so-called deep clone. You can create a method for that:
class FilterField {
// ... other code
FilterField CopyWith() {
return new FilterField(...);
}
}
and then you could something like that:
var newList = oldList.toList().map((item) => item.CopyWith()).toList();
and now you could change the lists separately.
But be aware that if FilterField has any other instances of classes that need to be changed you need to create new instances of those instances either. That's why it's called a deep clone.
Hope that's what you were looking for.
Related
Im trying to build a table with nested tree folder inside.
When trying to add nested data into the datasource data the structure will not updated and will not toggle anymore.
Code below:
https://stackblitz.com/edit/angular-table-tree-example-k2zqmt?file=app%2Ftable-basic-example.ts&file=app%2Ftable-basic-example.html,app%2Ftable-basic-example.ts
Environment
Angular:
Material Table
Material tree system
These are the things that are happening when logNode method is called
The item is getting added but the treeControl.toggle method does not work anymore.
When you are assigning a new dataset to the dataSource all the nodes get reset and the tree closes, so this.treeControl.toggle is trying to toggle a node that does not exist.
You need to find the node to be toggled from the list you get from treeControl.dataNodes
I would suggest having the toggle code in a separate method and adding a node code in a separate method, and a separate button to add the node.
The below code should work for your scenario, also remove this line from your HTML, (click)="treeControl.toggle(data)"
interface ExampleFlatNode {
expandable: boolean;
RoleName: string;
Access: boolean;
level: number;
CatId: number;
}
private transformer = (node: FoodNode, level: number) => {
return {
expandable:
!!node.CategoryPermissions && node.CategoryPermissions.length > 0,
RoleName: node.RoleName,
Access: node.Access,
level: level,
CatId: node.CatId,
};
};
tempNodes = []
constructor() {
this.dataSource.data = TREE_DATA;
}
logNode(clickedNode) {
this.tempNodes = [];
this.treeControl.dataNodes.forEach((node) =>
this.tempNodes.push({
...node,
expanded: this.treeControl.isExpanded(node),
})
);
if (!this.treeControl.isExpanded(clickedNode)) {
const temp = {
Access: true,
RoleName: 'test 1 2',
CatId: 113,
};
const clickedNodeIdx = this.treeControl.dataNodes.findIndex(
(node: any) =>
node.CatId === clickedNode.CatId &&
node.RoleName === clickedNode.RoleName &&
node.level === clickedNode.level
);
const childIdx = 1;
let child;
if (clickedNode.level === 0) {
child =
this.dataSource.data[clickedNodeIdx].CategoryPermissions[childIdx];
} else {
this.dataSource.data.forEach(
(item) => (child = this.findDataSource(item, clickedNode))
);
}
child.CategoryPermissions.push(temp);
this.dataSource.data = this.dataSource.data;
const addedNode = this.treeControl.dataNodes.find(
(node: any) =>
node.CatId === temp.CatId && node.RoleName === temp.RoleName
);
this.expandParent(addedNode);
this.setPreviousState();
} else {
this.treeControl.collapse(clickedNode);
}
}
findDataSource(item, node) {
if (item.RoleName === node.RoleName) {
return item;
} else if (item.CategoryPermissions) {
let matchedItem;
item.CategoryPermissions.forEach((e) => {
const temp = this.findDataSource(e, node);
if (temp) {
matchedItem = temp;
}
});
return matchedItem;
}
}
setPreviousState() {
for (let i = 0, j = 0; i < this.treeControl.dataNodes.length; i++) {
if (
this.tempNodes[j] &&
this.treeControl.dataNodes[i].RoleName === this.tempNodes[j].RoleName &&
this.treeControl.dataNodes[i].CatId === this.tempNodes[j].CatId &&
this.treeControl.dataNodes[i].level === this.tempNodes[j].level
) {
if (this.tempNodes[j].expanded) {
this.treeControl.expand(this.treeControl.dataNodes[i]);
}
j++;
}
}
}
expandParent(node: ExampleFlatNode) {
const { treeControl } = this;
const currentLevel = treeControl.getLevel(node);
const index = treeControl.dataNodes.indexOf(node) - 1;
for (let i = index; i >= 0; i--) {
const currentNode = treeControl.dataNodes[i];
if (currentLevel === 0) {
this.treeControl.expand(currentNode);
return null;
}
if (treeControl.getLevel(currentNode) < currentLevel) {
this.treeControl.expand(currentNode);
this.expandParent(currentNode);
break;
}
}
}
I have a list of map, so I want to check If the value I type contains any of the key value before adding.
here is my code:
for (var check in disciplineList) {
if (check.containsKey('degree') ||
!check.containsKey('degree')) {
if (check['degree'] != discipline.text) {
disciplineList.add({
'degree': discipline.text,
'date': currentDate
});
setState1(() {});
setState(() {});
discipline.clear();
currentDate = DateTime.now();
print(disciplineList);
} else {
openCustomDialog(
context: context,
body: '',
heading: 'Item Already Exists!');
print("Item Already Exists!");
}
}
}
In case you have some List of Maps listOfMaps and you want to check if it contains
1- a specific key
you can do so like this:
bool doesItContainKey(var key)
{
return listOfMaps.any((element) => element.keys.contains(key));
}
2- a specific value
you can do so like this:
bool doesItContainValue(var value)
{
return listOfMaps.any((element) => element.values.contains(value));
}
3- a specific map:
you can do so like this:
bool doesItContainMap(var map)
{
return listOfMaps.any((element) => element==map);
}
hey there i am trying to display all of the options from my database in a dropdown,i have them displaying but i only want one of each result to appear and i cant figure out how to to get ride of the duplicates this is what it looks like when i click on the dropdown
here is the code to pull in the results
void _getFieldsData() {
getUserDetails().then((data) {
final items = jsonDecode(data).cast<Map<String, dynamic>>();
var fieldListData = items.map<User>((json) {
return User.fromJson(json);
}).toSet().toList();
///set list for class
_selectedField = fieldListData[0].series;
_selectedField = fieldListData[0].classs;
setState(() {
for (Map user in items) {
_userDetails.add(User.fromJson(user));
print(_userDetails.length);
//if (_userDetails.classs != userDetail.classs.contains(_selectedText))
}
});
// update widget
setState(() {
_fieldList = fieldListData.toSet().toList();
//print(resultseries);
// print(uniqueCount);
print(_fieldList);
});
});
here is the dropdown
new DropdownButton<String>(
hint: Text("Series"),
// value: null,
items: _fieldList.map((value){
return DropdownMenuItem<String>(
value: value.series,
child: Container(
width: 100,
child: new Text(value.series),
it's not clear exactly what your User class looks like, but im assuming you have multiple fields that do not all have same values, for example, each with a unique id, that's why the following line isn't working in your case:
setState(() {
_fieldList = fieldListData.toSet().toList();
});
i would suggest using List.fold, List.any, and change the line above to check for only .series field, as below:
List initialResultsList = [];
setState(() {
// use fold (similar to .reduce()) to iterate through fieldListData and return the updated filtered 'results'
// list with each iteration:
_fieldList = fieldListData.fold(initialResultsList, (results, currentItem) {
// check to see if currentItem.series already exists in any item of filtered results:
if (!results.any((item) => item.series == currentItem.series)) {
// if not, add it to results:
results.add(currentItem);
}
// return results for next iteration
return results;
});
}
I am working no Timbre View Example of Famo.us, and what I am trying to achieve is simply open the page by clicking on strip view options in the app and closing the Menu Drawer as soon as I click on the Strip View option
for achieving this functionality I've read the Broad Cast and Listing from the Famo.us documentation. and wrote the following code in my example.
1) created a function to Broadcasting from an event handler with emit method and called it in Constructor of the Strip View.
Strip View:
define(function(require, exports, module) {
var View = require('famous/core/View');
var Surface = require('famous/core/Surface');
var Transform = require('famous/core/Transform');
var StateModifier = require('famous/modifiers/StateModifier');
var ImageSurface = require('famous/surfaces/ImageSurface');
var HeaderFooter = require('famous/views/HeaderFooterLayout');
var FastClick = require('famous/inputs/FastClick');
var check = true;
Boolean(check);
function StripView() {
View.apply(this, arguments);
_createBackground.call(this);
_createIcon.call(this);
_createTitle.call(this);
_setListenersForStripView.call(this);
}
StripView.prototype = Object.create(View.prototype);
StripView.prototype.constructor = StripView;
StripView.DEFAULT_OPTIONS = {
width: 320,
height: 55,
angle: -0.2,
iconSize: 32,
iconUrl: 'img/strip-icons/famous.png',
title: 'Famo.us',
fontSize: 26,
onload: 'StripView()'
};
function allFunctions()
{
_createBackground();
_createIcon();
_createTitle();
}
function _createBackground() {
this.backgroundSurface = new Surface({
size: [this.options.width, this.options.height],
properties: {
backgroundColor: 'black',
boxShadow: '0 0 1px black'
}
});
var rotateModifier = new StateModifier({
transform: Transform.rotateZ(this.options.angle)
});
var skewModifier = new StateModifier({
transform: Transform.skew(0, 0, this.options.angle)
});
this.add(rotateModifier).add(skewModifier).add(this.backgroundSurface);
// this.backgroundSurface.on("touchend", function(){alert("Click caught")})
}
function _createIcon() {
var iconSurface = new ImageSurface({
size: [this.options.iconSize, this.options.iconSize],
content: this.options.iconUrl,
pointerEvents: 'none'
});
var iconModifier = new StateModifier({
transform: Transform.translate(24, 2, 0)
});
this.add(iconModifier).add(iconSurface);
// iconSurface.on("click", function(){alert("Click caught")})
}
function _createTitle() {
this.titleSurface = new Surface({
size: [true, true],
pointerEvents: 'none',
content: this.options.title,
properties: {
color: 'white',
fontFamily: 'AvenirNextCondensed-DemiBold',
fontSize: this.options.fontSize + 'px',
textTransform: 'uppercase',
// pointerEvents : 'none'
}
});
var titleModifier = new StateModifier({
transform: Transform.thenMove(Transform.rotateZ(this.options.angle), [75, -5, 0])
});
this.add(titleModifier).add(this.titleSurface);
}
function _setListenersForStripView() {
this.backgroundSurface.on('touchend', function() {
this._eventOutput.emit('menuToggleforStripView');
alert('clicked on title');
}.bind(this));
}
module.exports = StripView;
});
2) Then created a Trigger Method in App View
App View:
define(function(require, exports, module) {
var View = require('famous/core/View');
var Surface = require('famous/core/Surface');
var Modifier = require('famous/core/Modifier');
var Transform = require('famous/core/Transform');
var StateModifier = require('famous/modifiers/StateModifier');
var Easing = require('famous/transitions/Easing');
var Transitionable = require('famous/transitions/Transitionable');
var GenericSync = require('famous/inputs/GenericSync');
var MouseSync = require('famous/inputs/MouseSync');
var TouchSync = require('famous/inputs/TouchSync');
GenericSync.register({'mouse': MouseSync, 'touch': TouchSync});
var PageView = require('views/PageView');
var StripView = require('views/StripView');
var MenuView = require('views/MenuView');
var StripData = require('data/StripData');
function AppView() {
View.apply(this, arguments);
this.menuToggle = false;
this.pageViewPos = new Transitionable(0);
this.stripViewPos = new Transitionable(0);
_createPageView.call(this);
_StripView.call(this);
_createMenuView.call(this);
_setListeners.call(this);
_handleSwipe.call(this);
_setListenersForStripView.call(this);
}
AppView.prototype = Object.create(View.prototype);
AppView.prototype.constructor = AppView;
AppView.DEFAULT_OPTIONS = {
openPosition: 276,
transition: {
duration: 300,
curve: 'easeOut'
},
posThreshold: 138,
velThreshold: 0.75
};
function _createPageView() {
this.pageView = new PageView();
this.pageModifier = new Modifier({
transform: function() {
return Transform.translate(this.pageViewPos.get(), 0, 0);
}.bind(this)
});
this._add(this.pageModifier).add(this.pageView);
}
function _StripView() {
this.stripView = new StripView();
this.stripModifier = new Modifier({
transform: function() {
return Transform.translate(this.stripViewPos.get(), 0, 0);
}.bind(this)
});
this._add(this.stripModifier).add(this.stripView);
}
function _createMenuView() {
this.menuView = new MenuView({stripData: StripData});
var menuModifier = new StateModifier({
transform: Transform.behind
});
this.add(menuModifier).add(this.menuView);
}
function _setListeners() {
this.pageView.on('menuToggle', this.toggleMenu.bind(this));
}
function _setListenersForStripView() {
this.stripView.on('menuToggleforStripView', this.toggleMenu.bind(this));
}
function _handleSwipe() {
var sync = new GenericSync(
['mouse', 'touch'],
{direction: GenericSync.DIRECTION_X}
);
this.pageView.pipe(sync);
sync.on('update', function(data) {
var currentPosition = this.pageViewPos.get();
if (currentPosition === 0 && data.velocity > 0) {
this.menuView.animateStrips();
}
this.pageViewPos.set(Math.max(0, currentPosition + data.delta));
}.bind(this));
sync.on('end', (function(data) {
var velocity = data.velocity;
var position = this.pageViewPos.get();
if (this.pageViewPos.get() > this.options.posThreshold) {
if (velocity < -this.options.velThreshold) {
this.slideLeft();
} else {
this.slideRight();
}
} else {
if (velocity > this.options.velThreshold) {
this.slideRight();
} else {
this.slideLeft();
}
}
}).bind(this));
}
AppView.prototype.toggleMenu = function() {
if (this.menuToggle) {
this.slideLeft();
} else {
this.slideRight();
this.menuView.animateStrips();
}
};
AppView.prototype.slideLeft = function() {
this.pageViewPos.set(0, this.options.transition, function() {
this.menuToggle = false;
}.bind(this));
};
AppView.prototype.slideRight = function() {
this.pageViewPos.set(this.options.openPosition, this.options.transition, function() {
this.menuToggle = true;
}.bind(this));
};
module.exports = AppView;
});
now what this code does, is create another strip overlapping the previous strips and it only works on the newly created strip view but not on the other strips which means when it comes back to srip view it loads only the DEFAULT_OPTIONS of strip view because the strip which is being generated newly and overlaping is titled famo.us
Please let me know where I am going wrong and how can I open a new view in my application by closing menu drawer.
Do you have a folder named 'data' with the 'StripData.js' file on your famo.us project?
I'm asking because I downloaded the the Starter Kit and I didn't find that file inside.
I am trying to add a customized mymenubutton, the menu's items are based on another dropdown's selected value, which returns a json array with bunch items.
So I use the example http://fiddle.tinymce.com/gaaaab which could create mymenubutton for the first time, but when the drop down list changes, how should I re-init this control and rebind json array to mymenubutton?
function generateTokensList(result) {
tinymce.create('tinymce.plugins.ExamplePlugin', {
createControl: function (n, cm) {
switch (n) {
case 'mysplitbutton':
var c = cm.createSplitButton('mysplitbutton', {
title: 'My split button',
image: 'some.gif',
onclick: function () {
alert('Button was clicked.');
}
});
c.onRenderMenu.add(function (c, m) {
m.add({ title: 'Tokens', 'class': 'mceMenuItemTitle' }).setDisabled(1);
var insertVar = function (val) {
return function () { tinyMCE.activeEditor.execCommand('mceInsertContent', false, val); }
};
for (var i = 0; i < result.length; i++) {
var field = result[i].field;
var variable = insertVar(result[i].field);
m.add({ title: result[i].name, onclick: variable });
}
});
// Return the new splitbutton instance
return c;
}
return null;
}
});
tinymce.PluginManager.add('example', tinymce.plugins.ExamplePlugin);
}
Solved this by myself. Bind the data to a variable and each time just call var.
c.onRenderMenu.add(function (c, m) {
m.add({ title: 'Tokens', 'class': 'mceMenuItemTitle' }).setDisabled(1);
var insertVar = function (val) {
return function () { tinyMCE.activeEditor.execCommand('mceInsertContent', false, val); }
};
for (var i = 0; i < tokens.length; i++) {
var field = tokens[i].field;
var variable = insertVar( '[['+tokens[i].name+']]');
m.add({ title: '[['+tokens[i].name+']]', onclick: variable });
}
});