This should be easy but I'm having a hard time figuring it out.
From within a plugin, how can I refer to a single point of a dataset?
const pulsePoint = {
id: 'pulsePoint',
afterDraw: chart => {
var point = chart.???
point.borderColor = '#ffffff'
chart.update()
}
You should access to dataset meta data by chart.getDatasetMeta(datasetIndex). You will get an object which represents the dataset. In the meta object, there is an array property, data, which contains all data elements(the points in your case). In each data element there is a object property, options, with the options of the element, where you can set the borderColor.
const pulsePoint = {
id: 'pulsePoint',
afterDraw: chart => {
const meta = chart.getDatasetMeta(0); // first dataset
const firstPoint = meta.data[0];
// Pay attention because it could be a loop. a condition should be set
if (firstPoint.options.borderColor !== '#ffffff') {
firstPoint.options.borderColor = '#ffffff';
chart.draw(); // better than update for this use case.
}
}
};
Related
I want to know if it's possible to train Dialogflow CX through API. By placing the new training phrases in my code (I am using NodeJS) and automatically update the list of phrases in that intent. One thing to add, I want to add a new phrase to the intent list no update an existing phrase.
Thank you in advance!
I was reading the documentation of Dialogflow CX and found this, https://github.com/googleapis/nodejs-dialogflow-cx/blob/main/samples/update-intent.js. But, this implementation will update a specific phrase instead of add it to the list.
Using the sample code that you have provided in your question, I updated it to show how to add a new phrase to the list. newTrainingPhrase will contain the training phrase, append newTrainingPhrase to intent[0].trainingPhrases and set updateMask to "training_phrases" to point to the part of the intent you would like to update.
See code below:
'use strict';
async function main(projectId, agentId, intentId, location, displayName) {
const {IntentsClient} = require('#google-cloud/dialogflow-cx');
const intentClient = new IntentsClient({apiEndpoint: 'us-central1-dialogflow.googleapis.com'});
async function updateIntent() {
const projectId = 'your-project-id';
const agentId = 'your-agent-id';
const intentId = 'your-intent-id';
const location = 'us-central1'; // define your location
const displayName = 'store.hours'; // define display name
const agentPath = intentClient.projectPath(projectId);
const intentPath = `${agentPath}/locations/${location}/agents/${agentId}/intents/${intentId}`;
//define your training phrase
var newTrainingPhrase = {
"parts": [
{
"text": "What time do you open?",
"parameterId": ""
}
],
"id": "",
"repeatCount": 1
};
const intent = await intentClient.getIntent({name: intentPath});
intent[0].trainingPhrases.push(newTrainingPhrase);
const updateMask = {
paths: ['training_phrases'],
};
const updateIntentRequest = {
intent: intent[0],
updateMask,
languageCode: 'en',
};
//Send the request for update the intent.
const result = await intentClient.updateIntent(updateIntentRequest);
console.log(result);
}
updateIntent();
}
process.on('unhandledRejection', err => {
console.error(err.message);
process.exitCode = 1;
});
main(...process.argv.slice(2));
I have a mutation to create a new card object, and I expect it should be added to the user interface after update. Cache, Apollo Chrome tool, and console logging reflect the changes, but the UI does not without a manual reload.
const [createCard, { loading, error }] = useMutation(CREATE_CARD, {
update(cache, { data: { createCard } }) {
let localData = cache.readQuery({
query: CARDS_QUERY,
variables: { id: deckId }
});
localData.deck.cards = [...localData.deck.cards, createCard];
;
client.writeQuery({
query: CARDS_QUERY,
variables: { id: parseInt(localData.deck.id, 10) },
data: { ...localData }
});
I have changed cache.writeQuery to client.writeQuery, but that didn't solve the problem.
For reference, here is the Query I am running...
const CARDS_QUERY = gql`
query CardsQuery($id: ID!) {
deck(id: $id) {
id
deckName
user {
id
}
cards {
id
front
back
pictureName
pictureUrl
createdAt
}
}
toggleDeleteSuccess #client
}
`;
I managed the same result without the cloneDeep method. Just using the spread operator solved my problem.
const update = (cache, {data}) => {
const queryData = cache.readQuery({query: USER_QUERY})
const cartItemId = data.cartItem.id
queryData.me.cart = queryData.me.cart.filter(v => v.id !== cartItemId)
cache.writeQuery({query: USER_QUERY, data: {...queryData}})
}
Hope this helps someone else.
Ok, finally ran into a long Github thread discussing their solutions for the same issue. The solution that ultimately worked for me was deep cloning the data object (I personally used Lodash cloneDeep), which after passing in the mutated data object to cache.writeQuery, it was finally updating the UI. Ultimately, it still seems like there ought to be a way to trigger the UI update, considering the cache reflects the changes.
Here's the after, view my original question for the before...
const [createCard, { loading, error }] = useMutation(CREATE_CARD, {
update(cache, { data: { createCard } }) {
const localData = cloneDeep( // Lodash cloneDeep to make a fresh object
cache.readQuery({
query: CARDS_QUERY,
variables: { id: deckId }
})
);
localData.deck.cards = [...localData.deck.cards, createCard]; //Push the mutation to the object
cache.writeQuery({
query: CARDS_QUERY,
variables: { id: localData.deck.id },
data: { ...localData } // Cloning ultimately triggers the UI update since writeQuery now sees a new object.
});
},
});
I am using following code to get the details of the object whose property is changed.
getChangedObject:function(){
console.log('changed name is' , can i get the object here );
}.observes('model.#each.rollNo')
Thanks in advance.
Inside observer you cant get the exact object which caused observer to trigger, but you can try the below approach, like iterating array of model and watch for changed attributes alone.
getChangedObject: function() {
let model = this.get('model');
model.forEach(function(item, index) {
var changedAttributes = item.changedAttributes();
item.eachAttribute(function(item, meta) {
var temp = changedAttributes[item];
if(temp){
console.log(' old value ',temp[0],' new value ',temp[1]);
}
});
})
}.observes('model.#each.rollNo')
I've been cracking my head for the last several days, trying to understand what am I doing wrong.
I'm implementing an infrastructure of lists for my app, which can include paging/infinite scroll/filtering/grouping/etc. The implementation is based on extending controllers (not array controllers, I want to be Ember 2.0 safe), with a content array property that holds the data.
I'm using Ember.computed.sort for the sorting, and it's working, but i have a strange behavior when i try to change the sorter. the sortedContent is not updating within the displayContent, even though the sortingDefinitions definitions are updated.
This causes a weird behaviour that it will only sort if I sort it twice, as if the sorting was asynchronous.
I am using Ember 1.5 (but it also happens on 1.8)
(attaching a snippet of code explaining my problem)
sortingDefinitions: function(){
var sortBy = this.get('sortBy');
var sortOrder = this.get('sortOrder') || 'asc';
if (_.isArray(sortBy)) {
return sortBy;
}
else {
return (sortBy ? [sortBy + ':' + sortOrder] : []);
}
}.property('sortBy', 'sortOrder'),
sortedContent: Ember.computed.sort('content', 'sortingDefinitions'),
displayContent: function() {
var that = this;
var sortBy = this.get('sortBy');
var sortOrder = this.get('sortOrder');
var list = (sortBy ? this.get('sortedContent') : this.get('content'));
var itemsPerPage = this.get('itemsPerPage');
var currentPage = this.get('currentPage');
var listItemModel = this.get('listItemModel');
return list.filter(function(item, index, enumerable){
return ((index >= (currentPage * itemsPerPage)) && (index < ((currentPage + 1) * itemsPerPage)));
}).map(function(item) {
var listItemModel = that.get('listItemModel');
if (listItemModel) {
return listItemModel.create(item);
}
else {
return item;
}
});
}.property('content.length', 'sortBy', 'sortOrder', 'currentPage', 'itemsPerPage')
Edit:
fixed by adding another dependency to the displayContent (sortedContent.[]):
displayContent: function() {
....
}.property('content.length', 'sortBy', 'sortOrder', 'currentPage', 'itemsPerPage' , 'sortedContent.[]')
Your sort function is watching the whole array sortingDefinitions instead of each element in the array. If the array changed to a string or some other variable it would update but not if an element in the array changes.
To ensure your computed property updates correctly, add a .[] to the end of the array so it looks like this: Ember.computed.sort('content', 'sortingDefinitions.[]')
I have a Phone model. I want to cache all phones on my application:
cachePhones : function () {
this.set('phones', this.Phone.find());
},
And get the countries for which I have available phones:
getCountries : function () {
var phones = this.get('phones.content');
var countries = new this.dataSet(), country;
console.log('phones=%o', phones.length);
for (var index = 0, length = phones.length; index < length; index++) {
country = phones[index].record.get('country');
console.log('Adding %o', country);
countries.add(country, true);
}
console.log('countries=%o', countries.keys());
return countries.keys();
},
(dataSet is just a set implementation in javascript)
I am not sure this is the right way to walk the ArrayController:
do I really need to access the content?
do I really need to access record?
This feels like hacking around my way in the ember internals. I have tried before this:
var phones = this.get('phones');
var countries = new this.dataSet(), country;
for (var index = 0, length = phones.length; index < length; index++) {
country = phones[index].country;
countries.add(country, true);
}
But it was not working at all. What is the canonical way of walking an ArrayController?
Have you tried something like this? Normally you should always be fine with using the functional methods Ember offers for its collections.
var phones = this.get('phones');
var countries = new this.dataSet(), country;
phones.forEach(function(phone, index){
country = phone.get("country");
countries.add(country, true);
});
Besides #mavilein correct answer one thing worth mentioning is that if you have a model like App.Phone then after you do App.Phone.find() and the records are fetched, your Store has already a cache which you can consult with App.Phone.all() this will not make another request but gives you the records available in the Store.
Hope it helps.