angular-slick carousel not working when using promise - slick.js

This is driving my crazy, the first angular-slick is not working but the second is just fine, any idea what is going on?
I created a plunkr (in case someone is looking for an example in the future), but my problem is very odd because in my code/realproject is not working so I don't know what the hell is going on, anyway! here is the plunkr: http://plnkr.co/edit/URIbhoVpm1OcLSQqISPs?p=preview
I think the problem is related to the DOM because maybe angular needs to create the html before the carousel is render, I don't know... :(
This is the outcome:
https://db.tt/noc0VgGU
Router:
(function() {
'use strict';
angular
.module('mgxApp.landing')
.config(configFunction);
configFunction.$inject = ['$routeProvider'];
function configFunction($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'app/landing/landing.html',
controller: 'homeCtrl',
controllerAs: 'hC'
});
}
})();
Controller:
(function() {
'use strict';
angular
.module('mgxApp.landing')
.controller('homeCtrl', homeCtrl);
homeCtrl.$inject = ['modalFactory', 'channelFactory'];
function homeCtrl(modalFactory, channelFactory) {
var hC = this;
hC.openAuthModal = modalFactory.openAuthModal;
hC.activeChannels;
channelFactory.allActiveChannels().then(function(activechannels){
console.log(activechannels);
hC.activeChannels = activechannels;
});
hC.w = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
hC.breakpoints = [
{
breakpoint: 768,
settings: {
slidesToShow: 2,
slidesToScroll: 2
}
}, {
breakpoint: 480,
settings: {
slidesToShow: 1,
slidesToScroll: 1
}
}
];
}
})();
HTML VIEW:
// NOT WORKING
<slick class="slider single-item" responsive="hC.breakpoints" slides-to-show=3 slides-to-scroll=3>
<div ng-repeat="channel in hC.activeChannels">
{{channel.get("username")}}
</div>
</slick>
// Working fine
<slick class="slider single-item" current-index="index" responsive="hC.breakpoints" slides-to-show=3 slides-to-scroll=3>
<div ng-repeat="i in hC.w">
<h3>{{ i }}</h3>
</div>
</slick>
Factory and Promise:
(function () {
'use strict';
angular
.module('mgxApp.channel')
.factory('channelFactory', channelFactory);
channelFactory.$inject = ['$rootScope', '$q'];
function channelFactory($rootScope, $q) {
var service = {
allActiveChannels : allActiveChannels
};
return service;
function allActiveChannels() {
var deferral = $q.defer();
var User = Parse.Object.extend("_User");
var query = new Parse.Query(User).limit(10);
query.find({
success: function(users) {
console.log(users);
/*for (var i = 0; i < users.length; i++) {
console.log(users[i].get("username"));
}*/
deferral.resolve(users);
},
error: function(error) {
console.warn(error);
deferral.reject();
}
});
return deferral.promise;
}
}
})();

My working code
<div tmob-slick-slider sliderData="" dynamicDataChange="true" class="utilHeightImg marqueeContainer">
<slick id="productCarousel" class="slider" settings="vm.slickAccessoriesConfig" data-slick='{"autoplay ": true, "autoplaySpeed": 4000}'>
<!-- repeat='image' -->
<div ng-repeat="slideContent in vm.slides track by $index" >
<div bind-unsafe-html="slideContent" ></div>
</div>
<!-- end repeat -->
</slick>
</div>
you have to write a directive to reinitialize the slider
angular.module('tmobileApp')
.directive('tmobSlickSlider',['$compile',function ($compile) {
return {
restrict: 'EA',
scope: true,
link: function (scope, element, attrs) {
scope.$on('MarqueesliderDataChangeEvent', function (event, data) {
$compile(element.contents())(scope);
});
}
};
}]);
Write this in your controller
hc.selectView=false; // make this hc.selectView=true when your promise get resolve
$scope.$watch('hc.selectView', function(newValue, oldValue) {
$scope.$broadcast('MarqueesliderDataChangeEvent');
});

I ended up using this solution:
Angular-slick ng-repeat $http get
I'd suggest you to use ng-if on slick element. That will only load slick directive only when data is present just by checking length of data.
Markup
<slick ng-if="ctrl.products.length">
<div ng-repeat="product in ctrl.products">
<img ng-src="{{product.image}}" alt="{{product.title}}"/>
</div>
</slick>

Related

OnClick Scroll JavaScript in SilverStripe

I want to make a single page website in SilverStripe. I want a smooth scroll on click using JavaScript but I can't get this to work correctly.
page.ss
<article>
<div class="bgs" style="background-image:url($BackgroundImage.URL);">
<div class="rows">
$Content
</div>
</div>
</article>
JavaScript
$('.menus-nav-item a').on('click', function() {
var $root = $('html, body'),
var $this = $(this),
href= $this.attr('href');
$root.animate({
scrollTop: $(href).offset().top - 20
}, 1000, function() {
window.location.hash = href;
});
I get the following errors:
Uncaught Error: Syntax error, unrecognized expression: /#who-we-are
and
Uncaught TypeError: Cannot read property 'top' of undefined while
calling the class attribute
found the answer!
$(function() {
$('a[href*=\\#]:not([href=\\#])').click(function() {
if (location.pathname.replace(/^\//,'') ==
this.pathname.replace(/^\//,'')
|| location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' +
this.hash.slice(1) +']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top -54
}, 1000);
return false;
}
}
});
});
});

How to compile template loaded from external api in Vue

I have a non-SPA web app that has Vue components and that works very well. However, I am looking for a way to load HTML that contains Vue via an external API.
So, I simply make a call to /ajax/dialogbox/client/add which is returning HTML containing Vue components, like:
<h1>Add client</h1>
<div>My static content</div>
<my-component></my-component>
but obviously <my-component></my-component> does not do anything.
In Angular 1 I was using $compile service to compile the HTML before output.
Is there a way to do the same in Vue?
There is a compile function available in Vue that compiles templates to render functions. Using the compiled functions requires a little more detail than you have provided (if you needed to use the returned template with data, for example), but here is one example.
console.clear()
Vue.component("my-component",{
template: `<h1>My Component</h1>`
})
const template = `
<div>
<h1>Add client</h1>
<div>My static content</div>
<my-component></my-component>
</div>
`
new Vue({
el: "#app",
data:{
compiled: null
},
mounted(){
setTimeout(() => {
this.compiled = Vue.compile(template)
}, 500)
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<div id="app">
<component :is="compiled"></component>
</div>
Note that in the example, I wrapped your example template in a div tag. Vue requires that there is on a single root element for a Vue or component.
After many hours, I managed to pass some properties to the component to be compiled.
In the HTML body:
<!-- some where in the HTML body -->
<div id="vCard2">
<component :is="compiled"></component>
</div>
<script>
var vmCard2 = new Vue({
el: '#vCard2',
data: {
compiled: null,
status: ''
},
methods: {
show: function () {
// macro is some dynamic string content or html template that contains mustache
var macro = this.status == 'some_switch' ? '...{{payment.status}}...' : '...{{refund.status}}...';
Vue.component('cp-macro', {
data: function () {
return {
payment: vmCard1.payment,
refund: vmCard1.refund
}
},
template: '<span>'+macro+'</span>'
})
this.compiled = Vue.compile('<cp-macro></cp-macro>');
},
hide: function () {
this.compiled = null; // must remove for the next macro to show
}
}
})
</script>
I use this method in my project for rendering templates as reactive component. All I need is passing in props URL for download template or template for immediate render:
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
<script>
const { createApp, defineComponent, markRaw } = Vue;
createApp({
template: `
<component v-if="component" :is="component"/>
<span v-else>Component is loading...</span>
`,
data: () => {
return {
component: undefined
}
},
provide: {
message: 'Hello Vue!'
},
mounted() {
setTimeout(async () => {
this.component = await this.defineRawComponent('<span>{{ message }}</span>')
}, 1000);
},
methods: {
async defineRawComponent(template, url) {
if (!template && !url) {
throw new Error('URL and template is not defined');
}
try {
let html = template;
if (!html) {
const { data } = await axios.get(url);
html = data;
}
return Promise.resolve(
markRaw(
defineComponent({
name: 'RawContent',
template: html,
inject: ['message']
})
)
);
} catch (err) {
return Promise.reject(err);
}
}
}
}).mount('#app')
</script>

ui-router state reverts to parent, and ui-view is cleared...why?

I'm implementing tabs in AngularJS, using ui-router. The problem is once I click on any of the links that are created, the state momentarily changes (as seen in the url) as well as ui-view is populated for a brief moment, then disappears. There are no styles associated with ui-view. Any ideas...?
The issue is in clicking a link on the ReportParent view (the parent).
Controller:
function ReportParentController($scope, $http, $q, $interval, ReportParentService, $stateParams, $state) {
var vm = this;
vm.dataArray = [];
vm.CustomerID = $stateParams.CustomerID;
vm.TabList = [];
ReportParentService.getReportList(vm.CustomerID).then(function (response) {
vm.TabData = response;
updateUrlValue(vm.TabData);
createTabList(vm.TabData);
});
function updateUrlValue(data) {
for (CurrentTabItem = 0; CurrentTabItem < data.length; CurrentTabItem++) {
data[CurrentTabItem].Url = "details.reportParent." + data[CurrentTabItem].NameNoSpaces + "Report";
}
}
function createTabList(data) {
for (CurrentTabItem = 0; CurrentTabItem < data.length; CurrentTabItem++) {
vm.TabList.push({ id: CurrentTabItem, Name: data[CurrentTabItem].Name, NameNoSpaces: data[CurrentTabItem].NameNoSpaces, Url: data[CurrentTabItem].Url });
}
}
}
View:
<div class="project-tab-menu ui right secondary menu" style="margin-right:1em;">
<a ng-repeat="Tab in vm.TabData" ui-sref={{Tab.Url}}>{{Tab.Name}}</a>
</div>
<div ui-view ></div>
Routing:
.state('details.reportParent.WindowsServerReport', {
url: '/windowsServerReport',
views: {
'#details.reportParent': {
templateUrl: 'Routing/WindowsServerReport',
controller: 'WindowsServerReportController',
controllerAs: 'vm',
},
},
})
.state('details.reportParent', {
url: '/reportParent',
templateUrl: 'Routing/ResultReportParent',
controller: 'ReportParentController',
controllerAs: 'vm'
});`
Turns out it's necessary to point to a ui-view on the parent, and using a url messes this up. Replace the details.reportParent route with the following
.state('details.reportParent', {
views: {
'resultsTab#details': {
templateUrl: 'Routing/ResultReportParent',
controller: 'ReportParentController',
controllerAs: 'vm'
},
},
});
Also make sure that in the parent view, you're putting data into a ui-view in this case <div ui-view ='resultsTab'></div>

ember model find query with params doesn't display on pagination

2I have an Ember app which connects to an api from where it gets articles. I make use of pagination to get 10 articles per request. This works. But now I wanted to add sorting to the request. I implemented this by using the extra parameter in the store.find.
However, for some reason if I use the 'return this.store.find('article', params);' instead of 'return this.store.find('article');' new articles (still requested and added correctly to the store!) in the getMore function are not beiing displayed or rendered. But when i remove the params parameter from store.find in model, it does work. What could be the case here?
templates/articles.hbs
<script type="text/x-handlebars" data-template-name="articles">
{{#each itemController="article"}}
<div class="item">
//...
</div>
{{/each}}
</script>
routes/articles.js
import Ember from 'ember';
export default Ember.Route.extend(Ember.UserApp.ProtectedRouteMixin, {
model: function(params) {
var params2 = {page: 1, per_page: 10, sort: params.sort};
return this.store.find('article', params2);
},
setupController: function(controller, model) {
controller.set('content', model);
},
actions:{
//...
},
getMore: function() {
// don't load new data if we already are
//if (this.get('loadingMore')) return;
//this.set('loadingMore', true);
var meta = this.store.metadataFor("article");
if (meta.hasmore) {
var controller = this.get('controller'),
nextPage = controller.get('page') + 1,
perPage = controller.get('perPage'),
sorting = controller.get('sort'),
items;
var params = {page: nextPage, per_page: perPage, sort: sorting};
this.store.findQuery('article', params).then(function (articles) {
controller.set('page', controller.get('page') + 1);
//this.set('loadingMore', false);
});
}
else{
$('#pagination_spinner').hide();
}
},
queryParamsDidChange: function() {
this.refresh();
}
}
});
controllers/articles.js
import Ember from 'ember';
var ArticlesController = Ember.ArrayController.extend({
itemController: 'article',
queryParams: ['sort'],
sort: 'rating',
page: 1,
perPage: 10
});
export default ArticlesController;
views/articles.js
import Ember from 'ember';
export default Ember.View.extend({
didInsertElement: function(){
//this.scheduleMasonry();
this.applyMasonry();
// we want to make sure 'this' inside `didScroll` refers
// to the IndexView, so we use jquery's `proxy` method to bind it
//this.applyMasonry();
$(window).on('scroll', $.proxy(this.didScroll, this));
},
willDestroyElement: function(){
this.destroyMasonry();
// have to use the same argument to `off` that we did to `on`
$(window).off('scroll', $.proxy(this.didScroll, this));
},
// this is called every time we scroll
didScroll: function(){
if (this.isScrolledToBottom()) {
$('#pagination_spinner').addClass('active');
this.get('controller').send('getMore');
}
},
scheduleMasonry: (function(){
Ember.run.scheduleOnce('afterRender', this, this.applyMasonry);
}).observes('controller.model.#each'), //TODO check
applyMasonry: function(){
$('#pagination_spinner').removeClass('active');
var $galleryContainer = $('#galleryContainer');
$galleryContainer.imagesLoaded(function() {
// check if masonry is initialized
var msnry = $galleryContainer.data('masonry');
if ( msnry ) {
msnry.reloadItems();
// disable transition
var transitionDuration = msnry.options.transitionDuration;
msnry.options.transitionDuration = 0;
msnry.layout();
// reset transition
msnry.options.transitionDuration = transitionDuration;
} else {
// init masonry
$galleryContainer.masonry({
itemSelector: '.item',
columnWidth: 0,
"isFitWidth": true
});
}
});
},
destroyMasonry: function(){
$('#galleryContainer').masonry('destroy');
},
// we check if we are at the bottom of the page
isScrolledToBottom: function(){
var distanceToViewportTop = (
$(document).height() - $(window).height());
var viewPortTop = $(document).scrollTop();
if (viewPortTop === 0) {
// if we are at the top of the page, don't do
// the infinite scroll thing
return false;
}
return (viewPortTop - distanceToViewportTop === 0);
}
});
nothing smart coming to my mind, but maybe it's that...
You've got the line:
if (meta.hasmore) {
in your getMore() function. Is this the case that you've got this meta field in one response and forgot in the other?

load google map geocoded in ajax page

I have a webapp where I load all my pages with ajax and now I´m trying to load a google map with the page below.
Problem solved, now I can load a google map with just an address(geocoded) with the below code.
<div id="map_external" class="notransform mapExternal">
<input id="address" type="hidden" value="kungsgatan 14,varberg,sweden">
<div id="header" class="toolbar">
<h1>Google Map</h1>
BACK
</div>
<div id="map_canvas" style=" height:600px!important;" class="notransform"></div>
<script>
jQuery(document).ready(function(){
$('#map_external').bind('pageAnimationStart', function(event, info){
if (info.direction == 'in') {
googleMaploadScript();
}
});
});
function googleMaploadScript() {
var script =document.createElement("script");
script.type="text/javascript";
script.src="http://maps.google.com/maps/api/js?sensor=false&callback=initialize";
document.body.appendChild(script);
//alert("script loaded");
}
var geocoder;
var map;
function initialize() {
geocoder = new google.maps.Geocoder();
var mapOptions = {
zoom: 15,
center: undefined,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
image = new google.maps.MarkerImage("http://www.mypage.com/images/googlemap/info.png",new google.maps.Size(32, 45));
shadowi = new google.maps.MarkerImage("http://www.mypage.com/images/googlemap/shadow.png",new google.maps.Size(51, 37));
codeAddress();
}
function codeAddress() {
var address = document.getElementById('address').value;
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location,
shadow: shadowi,
icon: image
});
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
}
</script>
</div>
Problem solved, see the above on how to load a geocoded google map in an ajax loaded page.

Resources