I am using a v-chip-group with v-chips to represent a tag cloud for records in my database. I have an object array with records that look something like { key:'device', count:100}. A record could have multiple tags, so as you click on a tag, a new query is made that filters on that tag, the result will then have a new tag cloud with a subset of the previous.
It looks something like this:
tag1 (1000), tag2 (100), tag3 (100)
When you click on tag1 you end up with:
tag1 (1000), tag3 (15) (no tag2 because there is no overlap between tag1 and tag2).
Here is the relevant template code:
<v-chip-group v-model="selectedTag" multiple #change="refresh">
<v-chip v-for="tag in tags" :key="tag.key" active-class="primary">
<v-avatar left class="grey">{{ tag.count }}</v-avatar>
{{ tag.key }}
</v-chip>
</v-chip-group>
The problem I have is that in the typescript I do something like this:
refresh() {
// get simple array of tag strings
const selectedTags = this.selectedTag.map((value: any) => {
if (this.tags && this.tags[value]) {
return this.tags[value].key
} else {
return null
}
}).filter((value: any) => {
return value != null
})
Promise.all([
...
ApiCall('GET', 'tags', {limit: 1000, tags: selectedTags}),
...
).then((values) => {
// decode response from server into new tags
this.tags = values[2].series['0'].values.map((item: any) => {
return {key: item.bucket, count: item.doc_count}
})
const newTags: number[] = []
this.tags.forEach((tag, index) => {
// find the new index of the previously selected tags and save them
if (selectedTags.find(st => {
return st === tag.key
})) {
newTags.push(index)
}
})
// update selectedTag with the new value
this.$set(this, 'selectedTag', newTags)
// did not work this.selectedTag = newTags
})
}
What I'm seeing is that when I click a chip, it correctly fires the #change event and calls refresh, but then when the refresh finishes, I see an additional refresh get called with an empty selectedTag, which clears my filters and recalls the above functionality.
Is there a way to get #change to fire when a chip is changed, but not fire (or filter it out) when the event is generated by changing the data referenced by v-model?
We have the list like below
List:
(("herry","0,1,2"),("herry","1,3"),("herry","3,6"),("herry","4"),("John","5"))
As the number in the string may be referred by different elements, the expected result is:
("herry","0,1,2,3,6"), ("herry","4"), ("John","5")
I worked out solution using scala, but it looks complicated, is there a more clean and easy way to work out the result? Thanks in advance!
Here is my solution in scala,
val foo=List(("herry","0,1,2"),("herry","1,3"),("herry","3,6"),("herry","4"),("John","5"))
println(GetValue)
def GetValue()={
foo.zipWithIndex.map((tuple: ((String, String), Int)) =>{
val tuples = getrelated(tuple._1, foo)
(tuple._2, tuples)
}).map((tuple: (Int, List[(String, String)])) => tuple._2)
.map((tuples: List[(String, String)]) => (tuples.head._1,tuples.map((tuple: (String, String)) => tuple._2)))
.map((tuple: (String, List[String])) => (tuple._1, tuple._2.mkString(",").split(",").distinct.sorted.mkString(",")))
.distinct
}
def getrelated(start:(String,String),fooList:List[(String,String)]):List[(String,String)]={
val fooListWithout = fooList.filter((tuple: (String, String)) => tuple != start)
val result=fooListWithout
.filter((tuple: (String, String)) => findmatching(tuple._2,start._2))
.flatMap((tuple: (String, String)) => start :: getrelated(tuple,fooListWithout))
if (result.isEmpty)
List(start)
else
result
}
def findmatching(key1:String,key2:String)={
(key1.split(",")++key2.split(","))
.groupBy(identity)
.mapValues((strings: Array[String]) => strings.size)
.exists((tuple: (String, Int)) => tuple._2>1)
}
Let me clarify the algorithm
if the number list has the overlapping number, then group these number as one element
if the number list has no overlapping number, then consider it as independent element
for example,
input: List(("herry","0,1,2"),("herry","1,3"),("herry","7,4"),("herry","4"),("John","5"))
expected output: List(("herry","0,1,2,3" ), ("herry","4,7"), ("John","5"))
input: List(("herry","0,1,2"),("herry","1,3"),("herry","3,6"),("herry","4"),("John","5"))
expected: List("herry","0,1,2,3,6"), ("herry","4"), ("John","5")
input: List(("herry","0,1"),("herry","2,3"),("herry","3,6"),("herry","4"),("John","5"))
expected: List("herry","0,1"),("herry","2,3,6"), ("herry","4"), ("John","5")
My assumption is that tuples for the same key that contain multiple values should be aggregated. It is unclear what should happen in the same value appears singly and as part of a list, e.g. ("herry", "4"), ("herry, "1,4") however it should be simple enough to remove any such cases
val data = List(("herry","0,1,2"),("herry","1,3"),("herry","3,6"),("herry","4"),("John","5"))// Start writing your ScalaFiddle code here
val (singles, multiples) = data.partition{case (name, list) => !list.contains(",")}
val multiplesAggregated = multiples
.groupBy{case (key, _) => key)
.map{
case (key, values) =>
key -> values.flatMap{case (_, numbers) => numbers.split(",")}.distinct.sorted.mkString(",")}.toList
println(multiplesAggregated ++ singles)
Output:
List((herry,0,1,2,3,6), (herry,4), (John,5))
Below I have a button that attempts to load remote content ...
import Post exposing (Post)
import Html exposing (..)
import Html.Events exposing (..)
import Http
import Json.Decode as Decode
type alias Model =
{ posts : List Post }
type Msg
= Search String
| PostsReceived (Result Http.Error (List Post))
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Search s ->
let
cmd =
(Decode.list Post.decode)
|> Http.get ("/posts?author=" ++ s)
|> Http.send PostsReceived
in
( model, cmd )
PostsReceived (Ok posts) ->
{ model | posts = posts }
! []
PostsReceived (Err error) ->
( model, Cmd.none )
view : Model -> Html Msg
view model =
button
[ onClick (Search "amelia") ]
[ text "Read posts by Amelia" ]
This is a valid Elm program, only there's one little problem: The API doesn't allow me to search by string. This is not allowed
/posts?author=amelia => Malformed Request Error
However, this is allowed
/posts?author=2 => [ {...}, {...}, ... ]
So I must first fetch an author to get his/her id, and then I can fetch posts using the author's id...
/author?name=amelia => { id: 2, name: "amelia", ... }
/posts?author=2
How can I sequence one request after the next? Ideally I'd like to cache the authors somewhere in the model so we're only requesting ones that we haven't seen before.
You can use Task.andThen to chain two tasks together. Assuming that the /posts response includes the author ID, you can then add that author ID into you model when you handle the response.
Search s ->
let
getAuthor =
Author.decode
|> Http.get ("/author?name=" ++ s)
|> Http.toTask
getPosts author =
(Decode.list Post.decode)
|> Http.get ("/posts?author=" ++ author.id)
|> Http.toTask
cmd =
getAuthor
|> Task.andThen getPosts
|> Task.attempt PostsReceived
in
( model, cmd )
I've got this compiling at https://ellie-app.com/DBJc6Kn3G6a1 if that helps
You can chain together tasks using Task.andThen. You'll first have to convert the web requests to tasks using Http.toTask:
postsByAuthorName : String -> Cmd Msg
postsByAuthorName name =
Http.get ("/author?name=" ++ name) (Decode.field "id" Decode.int)
|> Http.toTask
|> Task.andThen (\id ->
Http.get ("/posts?author=" ++ toString id) (Decode.list decodePost)
|> Http.toTask)
|> Task.attempt PostsReceived
A a dictionary and a couple more Msg options should do it.
You'll have to write the decoder for the Author response, but other than that this should work
type alias Model =
{ posts : List Post
, authors : Dict String Int }
type Msg
= Search String
| SearchAuthor String
| AuthorReceived (Result Http.Error Int String)
| PostsReceived (Result Http.Error (List Post))
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Search author ->
case (Dict.get author model.authors) of
Nothing ->
let
cmd =
(Decode.list Post.decode)
|> Http.get ("/author?name=" ++ author)
|> Http.send AuthorReceived
in
(model,cmd)
Just num ->
let
cmd =
(Decode.list Author.decode)
|> Http.get ("/posts?author=" ++ num)
|> Http.send PostsReceived
in
( model, cmd )
AuthorReceived (Ok number name) ->
let
updatedAuthors = Dict.inster name number model.authors
cmd =
(Decode.list Post.decode)
|> Http.get ("/posts?author=" ++ number)
|> Http.send PostsReceived
in
{model | authors = updatedAuthors } ! [cmd]
AuthorReceived (Err error) ->
(mode, Cmd.none )
PostsReceived (Ok posts) ->
{ model | posts = posts }
! []
PostsReceived (Err error) ->
( model, Cmd.none )
view : Model -> Html Msg
view model =
button
[ onClick (Search "amelia") ]
[ text "Read posts by Amelia" ]
Good afternoon,
I am using Clojure 1.8, PostgreSQL 9.4 and YeSQL 0.5.2
I have an web app that has a page to insert multiple prices. I get the prices from a HTML Form using Post method. It comes as a map of vector for me. I convert it to a vector of maps so it is easier to manipulate the data. Then I delete previous entries if exists and I do the treatments to the fields and call the DB transaction to insert into the database.
When I use lein ring server it works fine. But when I deploy to Tomcat 9 using lein ring uberwar, the app inserts only the last row.
Here are the my web page:
Each row in the table will be a SQL Insert
My connection:
(ns satus-cotacao.model.connection)
(def db-spec {:classname "org.postgresql.Driver"
:subprotocol "postgresql"
:subname "//localhost/database" ;; 192.168.0.x:port when using other database from the internal network.
:user "root"
:password "root"})
And my defqueries
(ns satus-cotacao.model.cotacao_model
(:require ...
[satus-cotacao.model.connection :refer [db-spec]]
...)
(defqueries "satus_cotacao/model/cotacao.sql"
{:connection db-spec})
The Post request that calls the lcto-cotacao-page using the Form as parameter
POST "/cotacao/:cod" [cod & form :as session] (lcto-cotacao-page cod form session))
The lcto-cotacao-page function to call the Delete and the Insert functions.
(defn lcto-cotacao-page
[cod lcto session]
(try
(cotacao/deleta-lcto-cotacao! cod (:identity session))
(cotacao/insere-lctos-cotacoes! cod (:identity session) lcto)
(layout/render "home.html" {:session session})
(catch Exception e
(do
(timbre/error e)))))
The delete-lcto-cotacao! function and SQL query
(defn deleta-lcto-cotacao!
[codcotacao enti_codigo]
(jdbc/with-db-transaction [tx db-spec]
(delete-lcto-cotacao! {:codcotacao codcotacao
:enti_codigo enti_codigo}
{:connection tx})))
-- name: delete-lcto-cotacao!
DELETE FROM lctocotacao
WHERE lcco_codentidade = :enti_codigo
AND lcco_codcontrole = :codcotacao
The delete works fine, it deletes all entries.
The insere-lctos-cotacoes! to convert from map of vector to vector of maps and create a recursive call through this vector
(defn insere-lctos-cotacoes!
[cod enti lctos]
(if (vector? (:lcco_codprod lctos))
(let [lcto-vec (util/from-map-of-vector-to-vector-of-maps lctos)]
(loop [lcto lcto-vec]
(when (not-empty lcto)
(insere-lcto-cotacao<! cod enti (first lcto))
(recur (rest lcto)))))
(insere-lcto-cotacao<! cod enti lctos)))
Then the function insere lcto-cotacao<! that treats the fields
(defn insere-lcto-cotacao<!
[cod enti lcto]
(let [lcto_codentidade enti
lcto_codcontrole cod
lcto_dtmvto (util/convert-to-data-type (.format (java.text.SimpleDateFormat. "MM/dd/yyyy") (Date.)))
lcto_codprod (Integer. (:lcco_codprod lcto))
lcto_qemb (bigdec (:lcco_qemb lcto))
lcto_qtde (bigdec (:lcco_qtde lcto))
lcto_fpgto (util/empty-field? (:lcco_fpgto lcto) false)
lcto_preco (util/empty-field? (:lcco_preco lcto) true)
lcto_codempresa (util/empty-field? (:lcco_codempresa lcto) false)
new-lcto (assoc lcto :lcco_codentidade lcto_codentidade
:lcco_codcontrole lcto_codcontrole
:lcco_dtmvto lcto_dtmvto
:lcco_codprod lcto_codprod
:lcco_preco lcto_preco
:lcco_qemb lcto_qemb
:lcco_qtde lcto_qtde
:lcco_fpgto lcto_fpgto
:lcco_codempresa lcto_codempresa)]
(insere-lcto-transaction<! (dissoc new-lcto :tpemb :descricao :codbarras :marca))))
And finally the insere-lcto-transaction<! and the SQL query
(defn insere-lcto-transaction<!
[lcto]
(jdbc/with-db-transaction [tx db-spec]
(insert-lcto-cotacao<! lcto {:connection tx})))
-- name: insert-lcto-cotacao<!
INSERT INTO lctocotacao (lcco_codentidade, lcco_codprod, lcco_preco, lcco_dtmvto, lcco_codempresa, lcco_fpgto, lcco_qemb, lcco_qtde, lcco_codcontrole)
VALUES(:lcco_codentidade, :lcco_codprod, :lcco_preco, :lcco_dtmvto, :lcco_codempresa, :lcco_fpgto, :lcco_qemb, :lcco_qtde, :lcco_codcontrole);
Well, thats it. What is strange is that it works fine when I do lein ring server, but when I deploy to lein ring uberwar it doens't work properly.
Also, I tried using Tomcat in Windows and Debian.
Does anyone have an idea why is it happening?
EDIT
After logging, I got some results:
When running local lein ring server
What the POST return into the var form is the same content as the key :param in my session
Also in session, I have the :form-paramsthat has the same content, but instead of using keys like :lcco_fpgto, it uses strings like '"lcco_fpgto"'
{:lcco_fpgto ["001" "001" "001" "001"],
:tpemb ["CX" "CX" "PT" "CX"],
:lcco_qtde ["150.00000" "1.00000" "30.00000" "1.00000"],
:descricao ["Cerveja 350ml Skola" "Adoc 100ml Assugrin Diet" "Cafe 500g Corol Torrado Moido" "Deterg Liq 500ml Alpes Neutro"],
:lcco_codprod ["19" "28" "64" "123"],
:lcco_preco ["1.00000" "2.00000" "3.00000" "4.00000"],
:codbarras ["7896232111149" "7896060010492" "7896184000010" "7896274800124"],
:lcco_codempresa ["001" "001" "001" "001"],
:lcco_qemb ["12.00000" "12.00000" "10.00000" "24.00000"],
:marca ["Skol" "Assugrin" "Corol" "Alpes"],
:__anti-forgery-token ["Unbound: #'ring.middleware.anti-forgery/*anti-forgery-token*" "Unbound: #'ring.middleware.anti-forgery/*anti-forgery-token*" "Unbound: #'ring.middleware.anti-forgery/*anti-forgery-token*" "Unbound: #'ring.middleware.anti-forgery/*anti-forgery-token*"]}
When running the deployed app:
The POST return is the same as the :param key inside session (Only the last element)
{:lcco_fpgto "001",
:tpemb "CX",
:lcco_qtde "1.00000",
:descricao "Deterg Liq 500ml Alpes Neutro",
:lcco_codprod "123",
:lcco_preco "4",
:codbarras "7896274800124",
:lcco_codempresa "001",
:lcco_qemb "24.00000",
:marca "Alpes",
:__anti-forgery-token "Unbound: #'ring.middleware.anti-forgery/*anti-forgery-token*"}
And what I found, is that the :form-params inside my session contains everything, but using strings instead of keys.
:form-params {
"lcco_preco" ["1" "2" "3" "4"],
"tpemb" ["CX" "CX" "PT" "CX"],
"descricao" ["Cerveja 350ml Skola" "Adoc 100ml Assugrin Diet" "Cafe 500g Corol Torrado Moido" "Deterg Liq 500ml Alpes Neutro"],
"lcco_codprod" ["19" "28" "64" "123"],
"lcco_fpgto" ["001" "001" "001" "001"],
"codbarras" ["7896232111149" "7896060010492" "7896184000010" "7896274800124"],
"marca" ["Skol" "Assugrin" "Corol" "Alpes"],
"lcco_qtde" ["150.00000" "1.00000" "30.00000" "1.00000"],
"__anti-forgery-token" ["Unbound: #'ring.middleware.anti-forgery/*anti-forgery-token*" "Unbound: #'ring.middleware.anti-forgery/*anti-forgery-token*" "Unbound: #'ring.middleware.anti-forgery/*anti-forgery-token*" "Unbound: #'ring.middleware.anti-forgery/*anti-forgery-token*"],
"lcco_qemb" ["12.00000" "12.00000" "10.00000" "24.00000"],
"lcco_codempresa" ["001" "001" "001" "001"]}
So, why is that happening? Is it wrong to use the var form that I get in here?
POST "/cotacao/:cod" [cod & form :as session] (lcto-cotacao-page cod form session))
Why is this difference happening?
EDIT 2
My middleware:
https://codeshare.io/mR7Zh