Страницы

Поиск по вопросам

понедельник, 3 декабря 2018 г.

Первый опыт в node.js Можно ли не переделывая с нуля получить сносный результат?

Мой первый опыт программирования, если не считать студенческих лабораторных на Delphi(и те были очень давно).
Цель: "приложение" которое на первой странице выдает кликабельный список из имен юзеров(имена берем в mongodb), а при клике на юзера перебрасывает на другую страницу, где уже отображает(беря из базы) подробные сведения о выбранном юзере. Основательно переписал, получил вот это.
Вопросы:
Общая структура более-менее адекватна? Дорабатывать имеющееся или же переделывать с нуля? В модуле userModel я подключаюсь к базе данных. Там предусмотрена простейшая обработка ошибки в виде сообщения в консоль. Как бы мне сделать так, чтобы эта ошибка попадала в express и я мог вывести в браузере объект ошибки?
//app.js: var express = require('express'); var app = express(); var router = require('./router/router'); app.use(router); app.listen(3000, function() { console.log('Listening on port 3000!
Database on mlab.com'); }); //router.js: var express = require('express'); GetFirstPage = require('../lib/GetPages').firstPage; GetSecondPage = require('../lib/GetPages').secondPage; var router = express.Router(); router.get('/', GetFirstPage); router.get('/user?:id', GetSecondPage); router.use(express.static('public')); module.exports = router; //userModel: const mongoose = require('mongoose'); mongoose.connect(require('../credentials').mongo, function(err) { if (err) console.log('Error database connection
', err) }); const userShema = mongoose.Schema({ name: String, age: String, disciplines: String, }); module.exports = mongoose.model('User', userShema); //GetPages.js: var express = require('express'); var app = express(); var _ = require('underscore'); const User = require('./exportFromDB').user; const NamesList = require('./exportFromDB').namesList; module.exports.firstPage = function(req, res) { Promise.all([ NamesList(), readMainPage() ]).then(function(results) { const list = results[0].map(function(item) { return item.name }) res.send(results[1]({ 'list': list })) }) } module.exports.secondPage = function(req, res) { Promise.all([ User(decodeURIComponent(req.query.id)), readSecondPage() ]).then(function(results) { res.send(results[1]({ name: results[0][0].name, age: results[0][0].age, disciplines: results[0][0].disciplines })) }) } function readMainPage() { const myFile = require('../lib/exportFile').mainPage; return myFile(); } function templateMainPage(template) { res.send(template({ 'list': List })) } function readSecondPage() { const myFile = require('../lib/exportFile').secondPage; return myFile(); } //ExportDB.js userModel = require('./userModel'); module.exports.namesList = () => { return new Promise(function(resolved, rejected) { userModel.find({}, 'name -_id', function(err, data) { resolved(data) }) }) } module.exports.user = (url) => { return new Promise(function(resolved, rejected) { userModel.find({ name: url }, function(err, data) { resolved(data) }) }) }


Ответ

Как-то так стандартно выглядит запрос страницы всех юзеров:
app.get('/', function(req, res) { users.find({}, (err, docs) => { res.locals.users = docs; res.render('list'); }; };
А в шаблоне страницы списка - юзеры выводятся в цикле each user in users, где каждый обёртывается в ссылку с атрибутом такого вида href="/users/#{user._id}" (или какой-там у вас синтаксис шаблонизатора)
А запрос страниц отдельных юзеров - app.get('/users/:id', ..., и в его обработчике, в объекте запроса значением параметра req.params.id будет айдишник юзера в базе, по которому он легко и запрашивается -
app.get('/users/:id', function(req, res) { users.find({_id: req.params.id}, (err, result) => { res.locals.user = result; res.render('user'); }; };
Шаблон страницы получил объект юзера - user._id user.name user.age и т.д. Всего и делов - спасибо ТиДжею Каравайчуку (или как там его) за Express.

Как правильно повернуть календарь?

Я не уверен, что мой подход правильный может есть другая идея?
Мне нужно имплементировать календарь в своем приложении с возможностью Range selection по датам.
Я для этого решил одну из самых популярных библиотек применить
https://github.com/prolificinteractive/material-calendarview
так как знаю, что Calendar View не приспособлен для Range selection
И все работает отлично пока не нужно поменять язык приложения с Английского на Иврит (так же как и Арабский слева направо)
Название месяцев меняется название дней недели тоже, но не меняется направление последовательности (оно тоже должно быть не rtl - cправа налево , а ltr - слева направо)
Вот скрин на англ

Вот как на иврите android:supportsRtl="false"

И тут тоже на иврите но android:supportsRtl="true" (не знаю почему но кроме того, что поменялось направление стрелок больше ничего)

Я нашел такой баг фикс как раз об этом
https://github.com/prolificinteractive/material-calendarview/pull/573
Это как раз то, что мне нужно, согласно этому фиксу направление должно меняться, но в моем случае видно, что это не так.
Что я делаю не так или подскажите, как можно это решить по другому?


Ответ

Вы можете использовать форк этого репозитория от того кто сделал этот коммит:
https://github.com/anasanasanas/material-calendarview
Придется использовать JitPack
В принципе, все предельно просто описано и на странице:
1 Пропишите:
allprojects { repositories { ... maven { url 'https://jitpack.io' } } }
2 Добавьте:
dependencies { ... compile 'com.github.anasanasanas:material-calendarview:1.4.4' }
Реультат:

Анимация JQuery. Как вернуть квадрат обратно?

Как при втором нажатии на кнопку вернуть квадрат обратно? Код ниже.

By default, all HTML elements have a static position, and cannot be moved. To manipulate the position, remember to first set the CSS position property of the element to relative, fixed, or absolute!



Ответ

используйте toggleclass и transition для плавности:
$("button").click(function(){ $("div").toggleClass('move_right'); }); div { left: 0px; transition: all .5s; background:#98bf21; height:100px; width:100px; position:absolute; } .move_right { left: 250px; }

By default, all HTML elements have a static position, and cannot be moved. To manipulate the position, remember to first set the CSS position property of the element to relative, fixed, or absolute!


Vue.js 2. Как можно сделать плавную анимацию используя v-for. (no JQ)

Есть страница с новостями, которая постоянно спустя 5 сек отправляет запрос на /getNews, ответ присваиваю в items. Далее через v-for происходит рендер блоков. Мне не нравиться, что они рендерятся сразу, я бы хотел какой нибудь плавности.
Код (News.vue):



Ответ

Для анимации списков надо использовать transition-group. https://vuejs.org/v2/guide/transitions.html#List-Transitions
Основные моменты:
элементы списка должны иметь уникальный ключ (задается через :key); по умолчанию элементы списка рендерятся в контейнер span, но это можно поменять использую атрибут tag;
И небольшой пример:
new Vue({ el: '#app', data() { return { items: [] } }, mounted() { setTimeout(() => { this.items = [ {id: 1, text: "Lorem ipsum"}, {id: 2, text: "Lorem ipsum"}, {id: 3, text: "Lorem ipsum"}, {id: 4, text: "Lorem ipsum"}, {id: 5, text: "Lorem ipsum"} ] }, 1000); } }) .item { height: 40px; width: 70px; border: 1px solid #ccc; margin: 5px; } .list-enter-active, .list-leave-active { transition: all 0.9s; opacity: 1; } .list-enter, .list-leave-to { opacity: 0; transform: translateX(50px) rotate(90deg); }

{{item.text}}

Максимальное количество чисел из массива, сумма которых не превосходит K

Здравствуйте. Дан массив A из N натуральных чисел. Нужно найти размер подмассива A максимальной длины, сумма элементов которого не превосходит K
Пример:
A = [1, 4, 2, 3] K = 6
Ответ: 3 (подмассив [1, 2, 3])
Правильно ли я думаю, что если отсортировать массив, то ответом будет количество первых элементов массива, сумма которых не превосходит К? И есть ли способ получше?


Ответ

Если ваша интерпретация постановки задачи действительно верна, то предложенный вам алгоритм - верен. Однако можно предложить более эффективное решение.
Вы можете применить обыкновенный алгоритм quick sort с дополнительной модификацией.
Если после выполнения partitioning оказывается, что сумма элементов в левой (меньшей) части массива не меньше чем K, то правая часть массива вас больше не интересует и тратить время на дальнейшую сортировку правой части никакого смысла нет. В случае же, когда сумма элементов в левой (меньшей) части массива меньше чем K, вы сразу знаете, что все элементы левой части заведомо входят в искомый подмассив и тратить время на дальнейшую сортировку левой части никакого смысла нет.
Это та же самая стратегия, по которой работает классический алгоритм поиска "k наименьших элементов", с той только разницей, что вы ищете не k наименьших элементов, а неизвестное число наименьших элементов, чья сумма не превосходит K
Таким образом на каждом уровне рекурсивного подразбиения вам нужно выполнять рекурсивный вызов только для одной половины подразбиения, в то время как вторая половина либо полностью игнорируется, либо просто целиком отправляется на выход (и затем игнорируется). Такой алгоритм должен легко допускать истинно циклическую реализацию, без использования стека.

Анимированное появление тени у path svg

Реализовала появление тени при наведении у path svg

#Projektablauf path { cursor: pointer; transition: all 0.3s ease; } #Projektablauf path:hover { filter: url(#dropshadow); }
Но как сделать появление тени плавным? transition: all 0.3s ease; не срабатывает.


Ответ

Можно продублировать ваши path, по умолчанию применить к ним ваш фильтр, поставить opacity:0 и отображать их при наведении на path без фильтра:
#Projektablauf path { cursor: pointer; transition: all 0.3s ease; } #Projektablauf path.hover { filter: url(#dropshadow); opacity: 0; pointer-events: none; } #Projektablauf path:hover+path.hover { opacity: 1; }
Ну, или отобраражать их при наведение на них самих:
#Projektablauf path { cursor: pointer; transition: all 0.3s ease; } #Projektablauf path.hover { filter: url(#dropshadow); opacity: 0; } #Projektablauf path.hover:hover { opacity: 1; }

Зачем в чужом коде тело конструктора вынесено в отдельный метод?

function A() { this._init.apply(this, arguments); }
A.prototype._init = function() { // ... }
let a = new A();
Не могу понять, зачем необходимо такое разделение? Зачем в теле конструктора вызывать другой метод в контексте того же объекта, если весь код, находящийся в теле конструктора можно поместить в сам конструктор? Какие преимущества дает такое разделение?
И еще. Зачем здесь вообще #apply()? Разве простой вызов this._init(arguments) не выполнит то же самое?


Ответ

Как оказалось, всё дело тут в хорошо запрятанной документации. В StyleGuide'ах обнаружилась инфа следующего вида:
Our pattern for writing classes is:
function Foo(arg1, arg2) { this._init(arg1, arg2); }
Foo.prototype = { _init: function(arg1, arg2) { this._myPrivateInstanceVariable = arg1; }, myMethod: function() {
}, myClassVariable: 42, myOtherClassVariable: 'Hello' }
Чем такое решение обусловлено, ответить не могу. А решение впихнуть сюда .apply(), как подсказал в комментариях к вопросу @Grundy обусловлено попыткой воссоздать функционал spread оператора. К слову, движок (GJS), интерпретирующий код, позволяет использовать spread. Поэтому конкретно в этом случае использование .apply() ничем не обусловлено, кроме, судя по всему, разве что незнания автора кода о существовании такого оператора.