Я создаю пользовательский компонент Page Pagrid в form.io, чтобы разрешить лицензию внутри сетки. Пейджер работает правильно для всех компонентов (текстовые поля, флажки и т. Д.), За исключением избранных компонентов (я использую Angular 19.2.0, @Formio/Angular: ^9.0.0, Formiojs: ^4.21.7)
, когда я добавляю избранные компоненты в ряд в ряд в строках в строках в районе и навигациями. Значение выбора мерцает или сбрасывает, обычно не выполняя первую доступную опцию, даже если базовые данные верны. /> TextField < /th>
select < /th>
< /tr>
< /thead>
1 < /td>
< /td>
< /tr>
< /td>
< /tr>
< /td> < /td> < /td> < /td> < /td> /> b < /td>
< /tr>
3 < /td>
c < /td>
< /tr>
4 < /td>
d < /td>
/> < /table> < /div>
На стр. 1 я вижу строки 1–3 (a, b, c). Значения хранятся правильно. Проблема заключается только в рендеринге пользовательского интерфейса компонента SELECT при переключении страниц. рендеринг и устойчивость ценности. Тем не менее, я не мог найти ничего, что напрямую объясняет, почему значение Select сбрасывается только при использовании внутри моего пользовательского пейджера для DataGrid, возможно, это проблема навыков. < /P>
Другие компоненты (например, текстовые поля) рендеринг на разных страницах, поэтому эта проблема, по -видимому, специфична для выбора. < /P>
Я также подтвердил, что < /p>
), поэтому проблема не в хранилище. /> Это мой код (см.: in app.component.ts , RediassionData имеет dal в 4 -й строке, но в таблице Aban отображается в 4 -й строке. Попробуйте изменить данные компонента, и перемещение между страницами): Sackblitz Пример
Начиная с пользовательских данных. Постоянно с другими компонентами. Прямо сейчас, сброс пользовательского интерфейса разрывает опыт работы с пользователем и делает его, похоже, данные были потеряны, даже если он все еще хранится.DataGridPager.js):
import { Formio } from "@formio/js";
import editForm from "./DataGridPager.form.js";
const Component = Formio.Components.components.component;
export default class DataGridPager extends Component {
static editForm = editForm;
static schema(...extend) {
return Component.schema(
{
type: "dataGridPager",
label: "Data Pager",
key: "dataGridPager",
pageLimit: 5,
gridToAttach: "",
},
...extend
);
}
static get builderInfo() {
return {
title: "Data Grid Pager",
icon: "list",
group: "basic",
weight: -100,
schema: DataGridPager.schema(),
};
}
constructor(component, options, data) {
super(component, options, data);
this.pageLimit =
Number(this.component.pageLimit) > 0
? Number(this.component.pageLimit)
: 5;
this.currentPageNum = 1;
this.totalPagesNum = 1;
this.totalRowsNum = 1;
this.allGridRows = [];
this.targetComponent = null;
}
render() {
return super.render(this.renderTemplate("dataGridPager"));
}
/**
* Called after render; wires refs, finds target component, and initializes UI.
*/
attach(element) {
// Let base class attach first
super.attach(element);
// Load refs from template
this.loadRefs(element, {
dataGridPager: "single",
firstItemNum: "single",
lastItemNum: "single",
totalItemsNum: "single",
currentPageNum: "single",
totalPagesNum: "single",
firstBtn: "single",
prevBtn: "single",
nextBtn: "single",
lastBtn: "single",
});
// Locate the grid/etc to attach to
this.targetComponent = this.findTargetComponent();
// If not found, show zero state and disable buttons
if (!this.targetComponent) {
this.allGridRows = [];
this.computeTotals();
this.updateUI();
this.setButtonsDisabled(true);
return;
}
// Verify it's actually a data grid component
if (this.targetComponent.component.type !== "datagrid") {
console.warn(
`DataGridPager: Component "${this.component.gridToAttach}" is not a data grid`
);
this.refs.dataGridPager.innerHTML = `Error: Attached component is not a data grid`;
this.allGridRows = [];
this.computeTotals();
this.updateUI();
this.setButtonsDisabled(true);
return;
}
// Compute totals and clamp current page
this.computeTotals();
// Wire button click handlers (store references for cleanup)
this._firstHandler = () => this.goToPage(1);
this._prevHandler = () => this.goToPage(this.currentPageNum - 1);
this._nextHandler = () => this.goToPage(this.currentPageNum + 1);
this._lastHandler = () => this.goToPage(this.totalPagesNum);
if (this.refs.firstBtn)
this.refs.firstBtn.addEventListener("click", this._firstHandler);
if (this.refs.prevBtn)
this.refs.prevBtn.addEventListener("click", this._prevHandler);
if (this.refs.nextBtn)
this.refs.nextBtn.addEventListener("click", this._nextHandler);
if (this.refs.lastBtn)
this.refs.lastBtn.addEventListener("click", this._lastHandler);
// Listen for changes inside the target component so edits persist across pages.
// Not all component implementations expose on/off; guard those calls.
this._targetChangeHandler = () => {
// read the current visible page rows from the target and merge them back
const currentPageData = Array.isArray(this.targetComponent.dataValue)
? JSON.parse(JSON.stringify(this.targetComponent.dataValue))
: [];
const offset = (this.currentPageNum - 1) * this.pageLimit;
// Remove the old slice and replace with new
this.allGridRows.splice(offset, this.pageLimit, ...currentPageData);
// Recompute totals in case rows were added/removed
this.computeTotals();
// If this page exceeds the limit, move to next page
if (currentPageData.length > this.pageLimit) {
this.goToPage(this.currentPageNum + 1);
} else {
// Otherwise just refresh this page
this.goToPage(this.currentPageNum);
}
};
this._targetDeleteHandler = () => {
// read the current visible page rows from the target and merge them back
const currentPageData = Array.isArray(this.targetComponent.dataValue)
? JSON.parse(JSON.stringify(this.targetComponent.dataValue))
: [];
if (currentPageData.length === 0 && this.currentPageNum > 1) {
// If we deleted the last item on this page, move back a page
this.currentPageNum--;
this.allGridRows.pop();
} else {
const offset = (this.currentPageNum - 1) * this.pageLimit;
// Remove the old slice and replace with new
this.allGridRows.splice(offset, this.pageLimit, ...currentPageData);
}
// Recompute totals in case rows were added/removed
this.computeTotals();
this.goToPage(this.currentPageNum);
};
if (typeof this.targetComponent.on === "function") {
this.targetComponent.on("change", this._targetChangeHandler);
this.targetComponent.on("dataGridDeleteRow", this._targetDeleteHandler);
} else if (typeof this.targetComponent.addEventListener === "function") {
// fallback (rare)
this.targetComponent.addEventListener(
"change",
this._targetChangeHandler
);
this.targetComponent.addEventListener(
"dataGridDeleteRow",
this._targetDeleteHandler
);
}
// Show initial page
this.goToPage(this.currentPageNum);
}
/**
* Find the target component by key (searches recursively from root)
*/
findTargetComponent() {
if (!this.root || !this.component?.gridToAttach) return null;
try {
return this.root.getComponent(this.component.gridToAttach);
} catch (e) {
return null;
}
}
/**
* Recalculate totals and clamp current page
*/
computeTotals() {
this.totalRowsNum = Array.isArray(this.allGridRows)
? this.allGridRows.length
: 1;
this.totalPagesNum = Math.max(
1,
Math.ceil(this.totalRowsNum / this.pageLimit)
);
if (this.currentPageNum < 1) this.currentPageNum = 1;
if (this.currentPageNum > this.totalPagesNum)
this.currentPageNum = this.totalPagesNum;
}
/**
* Show a specific page: slice items, set target value, update UI
*/
goToPage(pageNum) {
if (!this.targetComponent) return;
// ensure pageNum is always between 1 and totalPagesNum
const currentPageNum = Math.max(
1,
Math.min(pageNum || 1, this.totalPagesNum)
);
this.currentPageNum = currentPageNum;
const start = (currentPageNum - 1) * this.pageLimit;
const end = start + this.pageLimit;
const pageSlice = this.allGridRows.slice(start, end);
// Set the visible rows in the target component.
// setValue should exist on formio components; call defensively.
if (typeof this.targetComponent.setValue === "function") {
this.targetComponent.setValue(pageSlice);
} else {
// fallback: set dataValue directly (less ideal)
this.targetComponent.dataValue = pageSlice;
}
// Update UI text and button states
this.updateUI();
}
/**
* Update the DOM refs for numbers and button disabled states
*/
updateUI() {
// First/last item numbers: show 1 when no items
const firstNum =
this.totalRowsNum === 1
? 1
: (this.currentPageNum - 1) * this.pageLimit + 1;
const lastNum =
this.totalRowsNum === 1
? 1
: Math.min(this.currentPageNum * this.pageLimit, this.totalRowsNum);
if (this.refs.firstItemNum) this.refs.firstItemNum.innerText = firstNum;
if (this.refs.lastItemNum)
this.refs.lastItemNum.innerText = lastNum > 0 ? lastNum : 1;
if (this.refs.totalItemsNum)
this.refs.totalItemsNum.innerText =
this.totalRowsNum > 0 ? this.totalRowsNum : 1;
if (this.refs.currentPageNum)
this.refs.currentPageNum.innerText =
this.totalRowsNum === 1 ? 1 : this.currentPageNum;
if (this.refs.totalPagesNum)
this.refs.totalPagesNum.innerText = this.totalPagesNum;
// Button enable/disable
const onFirst = this.totalRowsNum === 1 || this.currentPageNum === 1;
const onLast =
this.totalRowsNum === 1 || this.currentPageNum === this.totalPagesNum;
if (this.refs.firstBtn) this.refs.firstBtn.disabled = onFirst;
if (this.refs.prevBtn) this.refs.prevBtn.disabled = onFirst;
if (this.refs.nextBtn) this.refs.nextBtn.disabled = onLast;
if (this.refs.lastBtn) this.refs.lastBtn.disabled = onLast;
}
/**
* enable/disable all buttons quickly
*/
setButtonsDisabled(disabled = true) {
if (this.refs.firstBtn) this.refs.firstBtn.disabled = disabled;
if (this.refs.prevBtn) this.refs.prevBtn.disabled = disabled;
if (this.refs.nextBtn) this.refs.nextBtn.disabled = disabled;
if (this.refs.lastBtn) this.refs.lastBtn.disabled = disabled;
}
/**
* Returns the full dataset (all pages) and the target component key
* for external use (e.g. on form submit)
*/
getAllGridRows() {
return [this.allGridRows, this.targetComponent.key];
}
/**
* Cleanup listeners when component is removed
*/
detach() {
// remove button listeners
if (this.refs.firstBtn && this._firstHandler)
this.refs.firstBtn.removeEventListener("click", this._firstHandler);
if (this.refs.prevBtn && this._prevHandler)
this.refs.prevBtn.removeEventListener("click", this._prevHandler);
if (this.refs.nextBtn && this._nextHandler)
this.refs.nextBtn.removeEventListener("click", this._nextHandler);
if (this.refs.lastBtn && this._lastHandler)
this.refs.lastBtn.removeEventListener("click", this._lastHandler);
// remove target change listener
if (this.targetComponent) {
if (typeof this.targetComponent.off === "function") {
if (this._targetChangeHandler)
this.targetComponent.off("change", this._targetChangeHandler);
if (this._targetDeleteHandler)
this.targetComponent.off(
"dataGridDeleteRow",
this._targetDeleteHandler
);
} else if (
typeof this.targetComponent.removeEventListener === "function"
) {
if (this._targetChangeHandler)
this.targetComponent.removeEventListener(
"change",
this._targetChangeHandler
);
if (this._targetDeleteHandler)
this.targetComponent.removeEventListener(
"dataGridDeleteRow",
this._targetDeleteHandler
);
}
}
return super.detach();
}
}
Подробнее здесь: https://stackoverflow.com/questions/797 ... -when-swit
Form.io DataGrid Custom Pager Компонент: выберите значение компонента сброс при переключении страниц ⇐ Javascript
Форум по Javascript
1759392677
Anonymous
Я создаю пользовательский компонент Page Pagrid в form.io, чтобы разрешить лицензию внутри сетки. Пейджер работает правильно для всех компонентов (текстовые поля, флажки и т. Д.), За исключением избранных компонентов [b] (я использую Angular 19.2.0, @Formio/Angular: ^9.0.0, Formiojs: ^4.21.7) [/b]
, когда я добавляю избранные компоненты в ряд в ряд в строках в строках в районе и навигациями. Значение выбора мерцает или сбрасывает, обычно не выполняя первую доступную опцию, даже если базовые данные верны. /> TextField < /th>
select < /th>
< /tr>
< /thead>
1 < /td>
< /td>
< /tr>
< /td>
< /tr>
< /td> < /td> < /td> < /td> < /td> /> b < /td>
< /tr>
3 < /td>
c < /td>
< /tr>
4 < /td>
d < /td>
/> < /table> < /div>
На стр. 1 я вижу строки 1–3 (a, b, c). Значения хранятся правильно. Проблема заключается только в рендеринге пользовательского интерфейса компонента SELECT при переключении страниц. рендеринг и устойчивость ценности. Тем не менее, я не мог найти ничего, что напрямую объясняет, почему значение Select сбрасывается только при использовании внутри моего пользовательского пейджера для DataGrid, возможно, это проблема навыков. < /P>
Другие компоненты (например, текстовые поля) рендеринг на разных страницах, поэтому эта проблема, по -видимому, специфична для выбора. < /P>
Я также подтвердил, что < /p>
), поэтому проблема не в хранилище. /> Это мой код (см.: in app.component.ts , RediassionData имеет dal в 4 -й строке, но в таблице Aban отображается в 4 -й строке. Попробуйте изменить данные компонента, и перемещение между страницами): Sackblitz Пример
Начиная с пользовательских данных. Постоянно с другими компонентами. Прямо сейчас, сброс пользовательского интерфейса разрывает опыт работы с пользователем и делает его, похоже, данные были потеряны, даже если он все еще хранится.DataGridPager.js):
import { Formio } from "@formio/js";
import editForm from "./DataGridPager.form.js";
const Component = Formio.Components.components.component;
export default class DataGridPager extends Component {
static editForm = editForm;
static schema(...extend) {
return Component.schema(
{
type: "dataGridPager",
label: "Data Pager",
key: "dataGridPager",
pageLimit: 5,
gridToAttach: "",
},
...extend
);
}
static get builderInfo() {
return {
title: "Data Grid Pager",
icon: "list",
group: "basic",
weight: -100,
schema: DataGridPager.schema(),
};
}
constructor(component, options, data) {
super(component, options, data);
this.pageLimit =
Number(this.component.pageLimit) > 0
? Number(this.component.pageLimit)
: 5;
this.currentPageNum = 1;
this.totalPagesNum = 1;
this.totalRowsNum = 1;
this.allGridRows = [];
this.targetComponent = null;
}
render() {
return super.render(this.renderTemplate("dataGridPager"));
}
/**
* Called after render; wires refs, finds target component, and initializes UI.
*/
attach(element) {
// Let base class attach first
super.attach(element);
// Load refs from template
this.loadRefs(element, {
dataGridPager: "single",
firstItemNum: "single",
lastItemNum: "single",
totalItemsNum: "single",
currentPageNum: "single",
totalPagesNum: "single",
firstBtn: "single",
prevBtn: "single",
nextBtn: "single",
lastBtn: "single",
});
// Locate the grid/etc to attach to
this.targetComponent = this.findTargetComponent();
// If not found, show zero state and disable buttons
if (!this.targetComponent) {
this.allGridRows = [];
this.computeTotals();
this.updateUI();
this.setButtonsDisabled(true);
return;
}
// Verify it's actually a data grid component
if (this.targetComponent.component.type !== "datagrid") {
console.warn(
`DataGridPager: Component "${this.component.gridToAttach}" is not a data grid`
);
this.refs.dataGridPager.innerHTML = `Error: Attached component is not a data grid`;
this.allGridRows = [];
this.computeTotals();
this.updateUI();
this.setButtonsDisabled(true);
return;
}
// Compute totals and clamp current page
this.computeTotals();
// Wire button click handlers (store references for cleanup)
this._firstHandler = () => this.goToPage(1);
this._prevHandler = () => this.goToPage(this.currentPageNum - 1);
this._nextHandler = () => this.goToPage(this.currentPageNum + 1);
this._lastHandler = () => this.goToPage(this.totalPagesNum);
if (this.refs.firstBtn)
this.refs.firstBtn.addEventListener("click", this._firstHandler);
if (this.refs.prevBtn)
this.refs.prevBtn.addEventListener("click", this._prevHandler);
if (this.refs.nextBtn)
this.refs.nextBtn.addEventListener("click", this._nextHandler);
if (this.refs.lastBtn)
this.refs.lastBtn.addEventListener("click", this._lastHandler);
// Listen for changes inside the target component so edits persist across pages.
// Not all component implementations expose on/off; guard those calls.
this._targetChangeHandler = () => {
// read the current visible page rows from the target and merge them back
const currentPageData = Array.isArray(this.targetComponent.dataValue)
? JSON.parse(JSON.stringify(this.targetComponent.dataValue))
: [];
const offset = (this.currentPageNum - 1) * this.pageLimit;
// Remove the old slice and replace with new
this.allGridRows.splice(offset, this.pageLimit, ...currentPageData);
// Recompute totals in case rows were added/removed
this.computeTotals();
// If this page exceeds the limit, move to next page
if (currentPageData.length > this.pageLimit) {
this.goToPage(this.currentPageNum + 1);
} else {
// Otherwise just refresh this page
this.goToPage(this.currentPageNum);
}
};
this._targetDeleteHandler = () => {
// read the current visible page rows from the target and merge them back
const currentPageData = Array.isArray(this.targetComponent.dataValue)
? JSON.parse(JSON.stringify(this.targetComponent.dataValue))
: [];
if (currentPageData.length === 0 && this.currentPageNum > 1) {
// If we deleted the last item on this page, move back a page
this.currentPageNum--;
this.allGridRows.pop();
} else {
const offset = (this.currentPageNum - 1) * this.pageLimit;
// Remove the old slice and replace with new
this.allGridRows.splice(offset, this.pageLimit, ...currentPageData);
}
// Recompute totals in case rows were added/removed
this.computeTotals();
this.goToPage(this.currentPageNum);
};
if (typeof this.targetComponent.on === "function") {
this.targetComponent.on("change", this._targetChangeHandler);
this.targetComponent.on("dataGridDeleteRow", this._targetDeleteHandler);
} else if (typeof this.targetComponent.addEventListener === "function") {
// fallback (rare)
this.targetComponent.addEventListener(
"change",
this._targetChangeHandler
);
this.targetComponent.addEventListener(
"dataGridDeleteRow",
this._targetDeleteHandler
);
}
// Show initial page
this.goToPage(this.currentPageNum);
}
/**
* Find the target component by key (searches recursively from root)
*/
findTargetComponent() {
if (!this.root || !this.component?.gridToAttach) return null;
try {
return this.root.getComponent(this.component.gridToAttach);
} catch (e) {
return null;
}
}
/**
* Recalculate totals and clamp current page
*/
computeTotals() {
this.totalRowsNum = Array.isArray(this.allGridRows)
? this.allGridRows.length
: 1;
this.totalPagesNum = Math.max(
1,
Math.ceil(this.totalRowsNum / this.pageLimit)
);
if (this.currentPageNum < 1) this.currentPageNum = 1;
if (this.currentPageNum > this.totalPagesNum)
this.currentPageNum = this.totalPagesNum;
}
/**
* Show a specific page: slice items, set target value, update UI
*/
goToPage(pageNum) {
if (!this.targetComponent) return;
// ensure pageNum is always between 1 and totalPagesNum
const currentPageNum = Math.max(
1,
Math.min(pageNum || 1, this.totalPagesNum)
);
this.currentPageNum = currentPageNum;
const start = (currentPageNum - 1) * this.pageLimit;
const end = start + this.pageLimit;
const pageSlice = this.allGridRows.slice(start, end);
// Set the visible rows in the target component.
// setValue should exist on formio components; call defensively.
if (typeof this.targetComponent.setValue === "function") {
this.targetComponent.setValue(pageSlice);
} else {
// fallback: set dataValue directly (less ideal)
this.targetComponent.dataValue = pageSlice;
}
// Update UI text and button states
this.updateUI();
}
/**
* Update the DOM refs for numbers and button disabled states
*/
updateUI() {
// First/last item numbers: show 1 when no items
const firstNum =
this.totalRowsNum === 1
? 1
: (this.currentPageNum - 1) * this.pageLimit + 1;
const lastNum =
this.totalRowsNum === 1
? 1
: Math.min(this.currentPageNum * this.pageLimit, this.totalRowsNum);
if (this.refs.firstItemNum) this.refs.firstItemNum.innerText = firstNum;
if (this.refs.lastItemNum)
this.refs.lastItemNum.innerText = lastNum > 0 ? lastNum : 1;
if (this.refs.totalItemsNum)
this.refs.totalItemsNum.innerText =
this.totalRowsNum > 0 ? this.totalRowsNum : 1;
if (this.refs.currentPageNum)
this.refs.currentPageNum.innerText =
this.totalRowsNum === 1 ? 1 : this.currentPageNum;
if (this.refs.totalPagesNum)
this.refs.totalPagesNum.innerText = this.totalPagesNum;
// Button enable/disable
const onFirst = this.totalRowsNum === 1 || this.currentPageNum === 1;
const onLast =
this.totalRowsNum === 1 || this.currentPageNum === this.totalPagesNum;
if (this.refs.firstBtn) this.refs.firstBtn.disabled = onFirst;
if (this.refs.prevBtn) this.refs.prevBtn.disabled = onFirst;
if (this.refs.nextBtn) this.refs.nextBtn.disabled = onLast;
if (this.refs.lastBtn) this.refs.lastBtn.disabled = onLast;
}
/**
* enable/disable all buttons quickly
*/
setButtonsDisabled(disabled = true) {
if (this.refs.firstBtn) this.refs.firstBtn.disabled = disabled;
if (this.refs.prevBtn) this.refs.prevBtn.disabled = disabled;
if (this.refs.nextBtn) this.refs.nextBtn.disabled = disabled;
if (this.refs.lastBtn) this.refs.lastBtn.disabled = disabled;
}
/**
* Returns the full dataset (all pages) and the target component key
* for external use (e.g. on form submit)
*/
getAllGridRows() {
return [this.allGridRows, this.targetComponent.key];
}
/**
* Cleanup listeners when component is removed
*/
detach() {
// remove button listeners
if (this.refs.firstBtn && this._firstHandler)
this.refs.firstBtn.removeEventListener("click", this._firstHandler);
if (this.refs.prevBtn && this._prevHandler)
this.refs.prevBtn.removeEventListener("click", this._prevHandler);
if (this.refs.nextBtn && this._nextHandler)
this.refs.nextBtn.removeEventListener("click", this._nextHandler);
if (this.refs.lastBtn && this._lastHandler)
this.refs.lastBtn.removeEventListener("click", this._lastHandler);
// remove target change listener
if (this.targetComponent) {
if (typeof this.targetComponent.off === "function") {
if (this._targetChangeHandler)
this.targetComponent.off("change", this._targetChangeHandler);
if (this._targetDeleteHandler)
this.targetComponent.off(
"dataGridDeleteRow",
this._targetDeleteHandler
);
} else if (
typeof this.targetComponent.removeEventListener === "function"
) {
if (this._targetChangeHandler)
this.targetComponent.removeEventListener(
"change",
this._targetChangeHandler
);
if (this._targetDeleteHandler)
this.targetComponent.removeEventListener(
"dataGridDeleteRow",
this._targetDeleteHandler
);
}
}
return super.detach();
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79780721/form-io-datagrid-custom-pager-component-select-component-value-resets-when-swit[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия