How would I bind styles using computed properties in VueJS while integrating with VueX.
The issue I am having is in regards to my style properties not updating after a change in my VueX Store.
Code Examples:
//VueX Store
const store = new Vuex.Store({
state : {
div: [
{
offset: 0,
width: 1,
text : 'Hello World'
},
{
offset: 0,
width: 1,
text : 'Hello World As Well'
}
]
}
});
//My component
<template>
<div v-bind:style="{ width: width, left: offset}">
<p>{{text}}</p>
</div>
</template>
<script>
export default {
name: 'divBox',
computed : {
text : function() {
return this.$store.state.div[this.Id].text;
},
width : function() {
return this.$store.state.div[this.Id].width;
},
offset : function() {
return this.$store.state.div[this.Id].offset;
}
},
props : ['Id']
}
</script>
Here is a working example of how to use vuex to do what you are wanting. https://jsfiddle.net/n9jmu5v7/770/ I assume your problem is the fact that your store does not contain any mutations https://vuex.vuejs.org/en/mutations.html.
mutations: {
bgChange: state => state.bg='grey',
colorChange: state => state.color='green'
}
Also, remember that just because your using vuex doesn't mean you need to put everything into it, it is fine to keep local data in a component. For example component style information sounds like something that doesn't need to be shared with anything else (Obviously you may have a reason for storing it in vuex that does make sense).
Related
Wants to open a mat-dialog on click of Detail Icon. But the issue is this is not referring to class. Its referring to the current grid.
constructor(private dialog: MatDialog) {}
ngOnInit() {
this.gridOptions = <GridOptions>{
rowSelection: 'multiple',
floatingFilter: true
};
this.gridOptions.columnDefs = [
{
headerName: 'Detail', field: '', filter: false, width: 80,
sortable: false,
onCellClicked: this.openModal,
cellRenderer: (data) => {
return `<mat-icon class="mat-icon material-icons" style="cursor:pointer;" aria-hidden="true">
keyboard_capslock</mat-icon>`;
}
},
{ headerName: 'Field Name', field: 'fieldName'}
];
openModal(row): void {
const detailRef = this.dialog.open(DetailComponent, {
height: '100vw',
width: '80vh',
direction: 'ltr',
data: {
record: row.data
}
});
Error: Unable to get property 'open' of undefined or null reference
Here this is referring to Grid and not to the class.
How can I refer to the class method to open the dialog?
Inline cellRenderer could be used only for simple cases.
If it's required to use functions inside or connect to third-party libraries, it has to be written as a custom cell renderer component.
I set up a nice map in my rails application. Everything is working fine but I cannot style the map with SnazzyMaps.
Here is my map.js file:
import GMaps from 'gmaps/gmaps.js';
const mapElement = document.getElementById('map');
if (mapElement) { // don't try to build a map if there's no div#map to inject in
const map = new GMaps({ el: '#map', lat: 0, lng: 0 });
const markers = JSON.parse(mapElement.dataset.markers);
const mapMarkers = map.addMarkers(markers);
mapMarkers.forEach((marker, index) => {
marker.addListener('click', () => {
// map.setCenter(markers[index]);
markers[index].infoWindow.open(map, marker);
})
});
if (markers.length === 0) {
map.setZoom(2);
} else if (markers.length === 1) {
map.setCenter(markers[0].lat, markers[0].lng);
map.setZoom(14);
} else {
map.fitLatLngBounds(markers);
}
}
import { autocomplete } from '../components/autocomplete';
// [...]
autocomplete();
On SnazzyMaps they give the following example. My question is, where shall I insert which part of this code in my own file. Been trying it for a while now but cannot make it work. Here is SnazzyMaps example:
<!DOCTYPE html>
<html>
<head>
<title>Snazzy Maps Super Simple Example</title>
<style type="text/css">
/* Set a size for our map container, the Google Map will take up 100% of this container */
#map {
width: 750px;
height: 500px;
}
</style>
<!--
You need to include this script tag on any page that has a Google Map.
The following script tag will work when opening this example locally on your computer.
But if you use this on a localhost server or a live website you will need to include an API key.
Sign up for one here (it's free for small usage):
https://developers.google.com/maps/documentation/javascript/tutorial#api_key
After you sign up, use the following script tag with YOUR_GOOGLE_API_KEY replaced with your actual key.
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=YOUR_GOOGLE_API_KEY"></script>
-->
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js"></script>
<script type="text/javascript">
// When the window has finished loading create our google map below
google.maps.event.addDomListener(window, 'load', init);
function init() {
// Basic options for a simple Google Map
// For more options see: https://developers.google.com/maps/documentation/javascript/reference#MapOptions
var mapOptions = {
// How zoomed in you want the map to start at (always required)
zoom: 11,
// The latitude and longitude to center the map (always required)
center: new google.maps.LatLng(40.6700, -73.9400), // New York
// How you would like to style the map.
// This is where you would paste any style found on Snazzy Maps.
styles: [{"featureType":"all","elementType":"geometry.fill","stylers":[{"weight":"2.00"}]},{"featureType":"all","elementType":"geometry.stroke","stylers":[{"color":"#9c9c9c"}]},{"featureType":"all","elementType":"labels.text","stylers":[{"visibility":"on"}]},{"featureType":"landscape","elementType":"all","stylers":[{"color":"#f2f2f2"}]},{"featureType":"landscape","elementType":"geometry.fill","stylers":[{"color":"#ffffff"}]},{"featureType":"landscape.man_made","elementType":"geometry.fill","stylers":[{"color":"#ffffff"}]},{"featureType":"poi","elementType":"all","stylers":[{"visibility":"off"}]},{"featureType":"road","elementType":"all","stylers":[{"saturation":-100},{"lightness":45}]},{"featureType":"road","elementType":"geometry.fill","stylers":[{"color":"#eeeeee"}]},{"featureType":"road","elementType":"labels.text.fill","stylers":[{"color":"#7b7b7b"}]},{"featureType":"road","elementType":"labels.text.stroke","stylers":[{"color":"#ffffff"}]},{"featureType":"road.highway","elementType":"all","stylers":[{"visibility":"simplified"}]},{"featureType":"road.arterial","elementType":"labels.icon","stylers":[{"visibility":"off"}]},{"featureType":"transit","elementType":"all","stylers":[{"visibility":"off"}]},{"featureType":"water","elementType":"all","stylers":[{"color":"#46bcec"},{"visibility":"on"}]},{"featureType":"water","elementType":"geometry.fill","stylers":[{"color":"#c8d7d4"}]},{"featureType":"water","elementType":"labels.text.fill","stylers":[{"color":"#070707"}]},{"featureType":"water","elementType":"labels.text.stroke","stylers":[{"color":"#ffffff"}]}]
};
// Get the HTML DOM element that will contain your map
// We are using a div with id="map" seen below in the <body>
var mapElement = document.getElementById('map');
// Create the Google Map using our element and options defined above
var map = new google.maps.Map(mapElement, mapOptions);
// Let's also add a marker while we're at it
var marker = new google.maps.Marker({
position: new google.maps.LatLng(40.6700, -73.9400),
map: map,
title: 'Snazzy!'
});
}
</script>
</head>
<body>
<h1>Snazzy Maps Super Simple Example</h1>
<h2>WY</h2>
<!-- The element that will contain our Google Map. This is used in both the Javascript and CSS above. -->
<div id="map"></div>
</body>
</html>
To set the style using Gmaps library, you need to define the styles and then set it to the current map as below:
const map = new GMaps({ el: '#map', lat: 0, lng: 0 });
var styles = [
{
stylers: [
{ hue: "#00ffe6" },
{ saturation: -20 }
]
}, {
featureType: "road",
elementType: "geometry",
stylers: [
{ lightness: 100 },
{ visibility: "simplified" }
]
}, {
featureType: "road",
elementType: "labels",
stylers: [
{ visibility: "off" }
]
}
];
map.addStyle({
styledMapName:"Styled Map",
styles: styles,
mapTypeId: "map_style"
});
map.setStyle("map_style");
Reference:
https://github.com/hpneo/gmaps/blob/master/examples/styled_maps.html
I have worked with several type of highcharts-ng, and the horizontal bar chart seems to be special - I had hard time to make the chart width adapt to the screen size. To illustrate the problem, I created a jsfiddle. By default, it has a fixed size of 600px, instead of the whole available width. I tried various ways to adjust the width accordingly, but none of them works perfectly. One way is to use $window.onresize as shown in the code, but it doesn't work. However, if I put a Resize button which runs the same code, it does work. Why?
HTML:
<div ng-app="myapp">
<div ng-controller="myctrl">
<input ng-model="chart.title.text">
<button ng-click="resize()">Resize</button>
<highchart id="chart1" series="chart.series" title="chart.title" options="chart.options"></highchart>
</div>
</div>
JS:
var myapp = angular.module('myapp', ["highcharts-ng"]);
myapp.controller('myctrl', function($scope, $window) {
$scope.resize = function() {
$scope.chart.options.chart.width = $window.innerWidth;
}
$window.onresize = function() {
$scope.chart.options.chart.width = $window.innerWidth;
}
$scope.chart = {
options: {
chart: {
type: 'bar'
}
},
series: [{
data: [10, 15, 12, 8, 7]
}],
title: {
text: 'Hello'
}
}
});
this in window.onresize refers to the global window object which does not have the chart config object in opposite to $scope.toggleWidth in which this refers to the scope with the chart.
Chart config can be accessed like this:
$window.onresize = function () {
var chart = $scope.chart.options.chart;
if (chart.width === 400) {
chart.width = 800
} else {
chart.width = 400
}
$scope.$digest();
};
onresize you need to manually call $digest().
example: http://jsfiddle.net/wscqtdvo/
Context
I have a small Ember app, which, amongst other things, displays a number of connected users and, when hovering an element of the page, their names as a list.
All in all, it works quite well. The applications pulls data from a REST endpoint every two minutes, as the backend didn't allow for pushing data.
The contents of the tooltip are computed in the Controller, with a function that basically concatenate strings in various ways according to the context. Then it's bound to a data attribute of the <img> the tooltip is created on. When the View is ready and didInsertElement is fired, the tooltip is generated (if needs be) based on this data-bindattr value.
Question
When new data is pulled from the backend, everything is updated accordingly, except the tooltip content. (When browsing the page's DOM, the data-bindattr value is updated too.)
What could cause the tooltip to not refresh? Is it a case of JQuery-UI not calculating it again?
Some code
Refreshing code in the app's controller:
Monitor.ApplicationController = Ember.ArrayController.extend({
itemController: 'process',
sortProperties: ['name'],
sortAscending: true,
intervalId: undefined,
startRefreshing: function() {
var self = this;
if (self.get('intervalId')) {
return;
}
self.set( 'intervalId', setInterval(function() {
self.store.find('process');
}, 120000 ));
}
});
View: Process.hbs
<div {{bind-attr class=":inline inactive:inactive"}}>
<img {{bind-attr src=icon}} {{bind-attr data-caption=contentText}} class="caption" />
<div class="counter">{{nbUsers}}</div>
</div>
View: ProcessView
Monitor.ProcessView = Ember.View.extend({
// (...) Various stuff.
didInsertElement: function() {
this.updateTooltip();
},
updateTooltip: function() {
console.log('Inside updateTooltip!');
if (!this.$()) {return;}
if (this.get('controller').get('inactive')) {
this.$().tooltip({items: '.caption', disabled: true});
return;
}
this.$().tooltip({
items: '.caption',
tooltipClass: 'tooltip',
content: function() {
return $(this).data('caption');
},
position: {
my: 'left+15px center',
at: 'right center',
collision: 'flip'
},
show: false,
hide: false
});
}.observes('controller.inactive', 'controller.contentText')
});
Controller: ProcessController
Monitor.ProcessController = Ember.ObjectController.extend({
contentText: function() {
var tooltipContent = '';
this.get('containers').forEach(function(container) {
// Do a lot of things to tooltipContent involving:
// container.get('name')
// container.get('text')
// container.get('size')
// container.get('nbUsers')
// The data-bindattr value refreshes correctly so I cut this out for readability.
return tooltipContent;
}.property('name', 'containers.#each')
});
Edit 1:
Replaced 'containers.#each' by 'contentText' in the observer and added logging.
Here's what I think is happening:
Your tooltip library isn't observing the data-caption attribute. Meaning, when you update the attribute, you have to explicitly tell the library to update the tooltip as well. So although your attribute is updating just fine, the tooltip library isn't actually watching for those updates.
This can be remedied by calling updateTooltip, which you do, in didInsertElement. However, didInsertElement only fires once, when the element is first inserted. It's not called when the content changes.
Those two things combined are, I think, causing your problem. I think that all you need to do is have updateTooltip also observe the controller.contextText property. Then it should be called when the text updates.
So it turns out my codes declares and initialize a tooltip, but once it's done, you can't change the content the same way. Plus it adds unneeded computing anyway.
Thanks to #GJK's answer and that question, I found out what was happening. Turns out you need to set the content of the tooltip to refresh it, not recreate it.
Here is the working code for Ember integration:
Monitor.ProcessView = Ember.View.extend({
// Other stuff
didInsertElement: function() {
this.initTooltip();
},
initTooltip: function() {
if (!this.$()) {return;}
if (this.get('controller').get('inactive')) {
this.$().tooltip({items: '.caption', disabled: true});
return;
}
this.$().tooltip({
items: '.caption',
tooltipClass: 'tooltip',
content: function() {
return $(this).data('caption');
},
position: {
my: 'left+15px center',
at: 'right center',
collision: 'flip'
},
show: false,
hide: false
});
},
updateTooltip: function() {
if (!this.$()) {return;}
if (this.get('controller').get('inactive')) {
this.$().tooltip({items: '.caption', disabled: true});
return;
}
content = this.get('controller').get('contentText');
this.$().tooltip("option", "content", content);
}.observes('controller.contentText')
});
As an added bonus, you can avoid using the data attribute as a buffer now, although I'm not sure why.
I am trying to add an option to a profile page for twitter widget and I have a field where users can add their twitter accounts and below it shows a preview of the widget. It works fine if I enter an account and click save and come back. But what I am trying to do is make it dynamic, to refresh the widget with corresponding account when blur event occurs on the text-field.
I have the following code:
var twitterWidget = new TWTR.Widget({
version: 2,
type: 'profile',
rpp: 4,
interval: 6000,
width: 'auto',
height: 300,
theme: {
shell: {
background: '#cccccc',
color: '#333333'
},
tweets: {
background: '#ffffff',
color: '#333333',
links: '#0099cc'
}
},
features: {
scrollbar: false,
loop: false,
live: false,
hashtags: true,
timestamp: true,
avatars: true,
behavior: 'all'
}
});
twitterWidget.setUser(twitterUser).render().start();
$('#twitter_widget_id').change(function(){
twitterWidget.setUser($(this).val()).render().start();
});
In this case it works wrong: it shows only the newest tweets from all the accounts that I entered and in general I'm getting an empty widget.
If I delete the object and create a new one it makes the page blank and then adds the widget.
Does anyone know some public methods for the TWTR.Widget() like re-render() or something like that?
Thanks.
The documented Twitter widget source code is available at http://twitter.com/javascripts/widgets/widget.js and reading through it will tell you everything you need to know about how to manipulate its behavior. Briefly, the widget works like this:
When the widget is first created with new TWTR.Widget it calls .init() and takes note of where it's embedded in the page, inserting the widget HTML code into the DOM at that position. (It always assumes you're embedding, which is why if you create a new widget in a head script or in the context of the window it will end up embedding itself in the root of the window.)
But, you can still create the widget using a function (as long as it's called from the embedded script) and then hold onto a reference to the widget for later. When you call .render() later the widget just re-renders itself wherever it happens to be.
There are some pseudo-private methods on the TWTR object that you might try for fun, such as _getWidgetHtml() - which is called by .render() but you shouldn't need to use those.
I just wrote the following code, and it works well for me. Call this function from your embedded script (as shown), then call it again later with a new search parameter to re-render it.
<div id="my_widget_region">
<script src="http://widgets.twimg.com/j/2/widget.js"></script>
<script>do_twitter_widget('"#winning" or "justin bieber"');</script>
</div>
function do_twitter_widget(search_query, title, subtitle) {
if (!window.widgetRef) {
window.widgetRef = new TWTR.Widget({
version: 2,
type: 'search',
search: search_query,
interval: 6000,
title: title || 'Tweets related to',
subject: subtitle || search_query,
width: 'auto',
height: 500,
theme: {
shell: {
background: '#8EC1DA',
color: '#FFFFFF'
},
tweets: {
background: '#FFFFFF',
color: '#444444',
links: '#1985B5'
}
},
features: {
scrollbar: false,
loop: true,
live: true,
hashtags: true,
timestamp: true,
avatars: true,
behavior: 'default'
},
ready: function() {
// when done rendering...
}
});
window.widgetRef
.render()
.start();
}
else {
if (search_query != window.old_twitter_search) {
window.widgetRef
.stop()
.setSearch(search_query)
.setTitle(title || 'Tweets related to')
.setCaption(subtitle || search_query)
.render()
.start();
}
}
window.old_twitter_search = search_query;
return window.widgetRef;
}
You can just reload the widget by create a new instance using "id" params as html id of the the widget element.
Exemple below. (Works fine for me)
window.twitterCreateOrUpdateProfile = function (username) {
var opts = {
version: 2,
type: 'profile',
rpp: 4,
interval: 30000,
width: 298,
height: 320,
theme: {
shell: {
background: '#86b9d1',
color: '#ffffff'
},
tweets: {
background: '#ffffff',
color: '#444444',
links: '#0b0d0d'
}
},
features: {
scrollbar: true,
loop: false,
live: false,
behavior: 'all'
}
};
if (window.twitterCreateOrUpdateProfile.instance) {
opts.id = window.twitterCreateOrUpdateProfile.instance.widgetEl.id;
}
window.twitterCreateOrUpdateProfile.instance = new TWTR.Widget(opts);
window.twitterCreateOrUpdateProfile.instance.render().setUser(username).start();
}
window.twitterCreateOrUpdateProfile('evaisse');