Yesterday I find solution for my angular carousel,
but its has some issue with binding.
Every time data of carousel should changing and now this example doesn't work , but when i add :: before openGame.availableMarketGroups in HTML ng-repeat , its works , but one time binding only .
How can i fix it ?
Any ideas ?
Thanks
The source
VBET5.directive("owlCarousel", function() {
return {
restrict: 'E',
transclude: false,
link: function (scope) {
scope.initCarousel = function(element) {
// provide any default options you want
var defaultOptions = {
};
var customOptions = scope.$eval($(element).attr('data-options'));
// combine the two options objects
for(var key in customOptions) {
defaultOptions[key] = customOptions[key];
}
// init carousel
var curOwl = $(element).data('owlCarousel');
if(!angular.isDefined(curOwl)) {
$(element).owlCarousel(defaultOptions);
}
scope.cnt++;
};
}
};
})
.directive('owlCarouselItem', [function() {
return {
restrict: 'A',
transclude: false,
link: function(scope, element) {
// wait for the last item in the ng-repeat then call init
if(scope.$last) {
scope.initCarousel(element.parent());
}
}
};
}]);
Here is the HTML
<data-owl-carousel data-options="{navigation: true, pagination: false, rewindNav : true}">
<div class="market-carousel">
<div owl-carousel-item="" class="carousel-item"
ng-repeat="group in openGame.availableMarketGroups track by group.id">
<span>...</span>
</div>
</div>
</data-owl-carousel>
Related
I tried to convert the normal jQuery own carousel into Angular Directive. It doesn't work for me, show some angular errors which I couldn't find what is the issue.
Controller
$scope.defaultsCarousel = {
'items': 4,
'itemWidth': 300,
'itemsDesktop': [1260, 3],
'itemsTablet': [930, 2],
'itemsMobile': [620, 1],
'navigation': true,
'navigationText': false
};
HTML (Jade)
custom-carousel(data-options="{{ defaultsCarousel }}", productid="#pl-1")
Directive
myApp.directive('customCarousel', function(){
function nextSlide(e) {
e.preventDefault();
e.data.owlObject.next();
};
function prevSlide(e) {
e.preventDefault();
e.data.owlObject.prev();
};
return{
restrict: 'E',
scope: {},
link: function($scope, el, attrs){
var options = $scope.$eval($(el).attr('data-options'));
var product_id = attrs.productid;
console.log(product_id);
$(product_id).owlCarousel(options);
var owl = $(product_id).data('owlCarousel');
$(product_id).parent().find('.slide-control.right').on('click', {owlObject: owl}, nextSlide);
$(product_id).parent().find('.slide-control.left').on('click', {owlObject: owl}, prevSlide);
}
}
ERROR
Syntax Error: Token '{' invalid key at column 2 of the expression [{{] starting at [{4}].
Your problem is at this line $scope.$eval($(el).attr('data-options'));. This produce a parse syntax error. You have two options to fix it:
OPTION 1: get the options from attrs parameter of link directive function. (PLUNKER)
app.directive('customCarousel', function() {
return {
restrict: 'E',
link: function(scope, el, attrs) {
var options = angular.fromJson(attrs.options);
var product_id = attrs.productid;
//..Rest of your logic
}
}
});
OPTION 2: get the options using scope one way binding. (PLUNKER)
app.directive('customCarousel', function() {
return {
restrict: 'E',
scope: {
options: '#',
productid: '#'
},
link: function(scope, el, attrs) {
var options = angular.fromJson(scope.options);
var product_id = scope.productid;
//..Rest of your logic
}
}
});
As you can see I'm getting the html data-options attribute as just options. That's because angularjs directives will ignore data-* prefix in all HTML elements and attributes names.
More info:
Check this post about difference between ng-app and data-ng-app
Check basic data-* prefix docs in W3Schools
I am using ng-repeat to view PS4 games data from json file inside a owl carousel like that:
<data-owl-carousel class="owl-carousel" data-options="{navigation: true, pagination: false, rewindNav : false}">
<owl-carousel-item ng-repeat="game in $ctrl.games | filter: $ctrl.query" class="item">
<a href="#!/games/{{game.id}}" class="thumb">
<img ng-src="{{game.imageUrl}}" />
<p id="gamenamebox"> {{game.name}} </p>
</a>
<p> Genre: {{game.genre}} </p>
now as you can see i added a filter for $ctrl.query and just added it to a search input like that:
Search for game:
<input ng-model="$ctrl.query"/>
now, everything is working great, all info is in the carousel and looks like this:
working great
but once i search in the search input and delete the game name i was searching for everything breaks to a line like that:
breaks
Does anyone know how can i fix it?
Thanks in advance.
this is the javascript code by the way:
.directive("owlCarousel", function() {
return {
restrict: 'E',
transclude: false,
link: function (scope) {
scope.initCarousel = function(element) {
// provide any default options you want
var defaultOptions = {
};
var customOptions = scope.$eval($(element).attr('data-options'));
// combine the two options objects
for(var key in customOptions) {
defaultOptions[key] = customOptions[key];
}
// init carousel
$(element).owlCarousel(defaultOptions);
};
}
};
})
.directive('owlCarouselItem', [function() {
return {
restrict: 'E',
transclude: false,
link: function(scope, element) {
// wait for the last item in the ng-repeat then call init
if(scope.$last) {
scope.initCarousel(element.parent());
}
}
};
}]);
I am trying to make custom directive to display:
Will {{selectedAsset}} go {{red}} or {{green}}?
It looks like this on the screen:
AUD/USD will down(red color) or up(green color)?
The {{red}} and {{green}} part should have its own color . Hence I am trying to wrap it with a span having desired classes.
But it is not working, below is the code:
<trade-header selected-asset="selectedAsset" red="widgetMessage.goDown" green="widgetMessage.goUp"></trade-header>
var widgetMessage = {
"Trade_Header": "Will {{selectedAsset}} go {{red}} or {{green}}?",
"goUp": "up",
"goDown": "down"}
myApp.directive("tradeHeader", function($sce) {
return {
restrict: "AE",
scope: {
selectedAsset: "=",
green:"=",
red:"="
},
link: function(scope, element, attrs) {
scope.green = $sce.trustAsHtml('<span class="goOrDonwLabel upGreen">' + scope.green + '</span>');
},
template: widgetMessage.Trade_Header,
}
});
widgetMessage.Trade_Header need to be variable cause the design.
This consequence will be : "AUD/USD will down or <span class="Green">up</span>?"
I need it to be compiled as HTML, any suggestions?
Your html should be in the template. When you're trying to manipulate HTML in code, that's usually a sign you're not using templates the right way. Try something like this:
<trade-header selected-asset="selectedAsset" red="widgetMessage.goDown" green="widgetMessage.goUp"></trade-header>
var widgetMessage = {
"Trade_Header": 'Will {{selectedAsset}} go {{red}} or <span ng-class="greenLabel">{{green}}</span>?',
"goUp": "up",
"goDown": "down"}
myApp.directive("tradeHeader", function($sce) {
return {
restrict: "AE",
scope: {
selectedAsset: "=",
green:"=",
red:"="
},
link: function(scope, element, attrs) {
scope.greenLabel = widgetMessage.goUp; // logic for setting green's class here
},
template: widgetMessage.Trade_Header,
}
});
Here is my plnkr with my progress so far: http://plnkr.co/edit/iEHMUMlASZaqdMQUeF7J?p=preview
I'm having problems implementing the following functionality however.
When an item on the list is clicked, I need to disable the remaining items on the list. ie, another request should not take place, and these remaining items' colour should change to indicate the disabled state.
Once the request has taken place, then the entire list should go back to the original state.
Edit: I've made some progress. Although a bit messy it's getting me a bit closer. My problem is the following line:
$(this).parent().addClass('item-selected').children().unbind('click').removeClass('pending');
This prevents the click event running more than once at a time. However it's stopping the click event from running all together once its run for the first time. I would like to be able to re-run the process once it is complete an unlimited amount of times.
Directive:
app.directive('listItem', function (ListService, $timeout, $location) {
return {
restrict: 'ACE',
controller : 'ItemController',
template: '<p>{{item}} {{foo}}</p>',
link: function (scope, element, attrs) {
$(element).bind('click', function (e) {
$(this).parent().addClass('item-selected').children().unbind('click').removeClass('pending');
$(this).addClass('pending');
var elem = $(this);
$timeout(function () {
ListService
.selectItem(scope.item)
.then( function () {
console.log('success');
elem.removeClass('pending').addClass('success');
//$location.path('foo.html')
scope.foo = 'not bar';
}, function () {
console.log('error');
elem.removeClass('pending').addClass('error');
elem.parent().removeClass('item-selected');
});
;
}, 2000);
});
}
};
});
The entire app code including directive:
var app = angular.module('listtestApp', []);
app.service('ListService', function ($http) {
var data = [
'alpha',
'bravo',
'charlie',
'delta',
'foxtrot'
];
return {
getData : function () {
return data;
},
selectItem : function () {
return $http({ method: 'GET', url : '/data/list.json'});
}
}
});
app.controller('ListController', function ($scope, ListService) {
$scope.list = ListService.getData();
$scope.foo = 'Bar';
});
app.controller('ItemController', function ($scope, ListService) {
});
app.directive('listItem', function (ListService, $timeout, $location) {
return {
restrict: 'ACE',
controller : 'ItemController',
template: '<p>{{item}} {{foo}}</p>',
link: function (scope, element, attrs) {
$(element).bind('click', function (e) {
$(this).parent().addClass('item-selected').children().unbind('click').removeClass('pending');
$(this).addClass('pending');
var elem = $(this);
$timeout(function () {
ListService
.selectItem(scope.item)
.then( function () {
console.log('success');
elem.removeClass('pending').addClass('success');
//$location.path('foo.html')
scope.foo = 'not bar';
}, function () {
console.log('error');
elem.removeClass('pending').addClass('error');
});
;
}, 2000);
});
}
};
});
html markup below:
<body ng-app="listtestApp">
<div ng-controller="ListController">
<div ng-repeat="item in list" list-item>
</div>
</div>
</body>
You have several solutions at your disposal :
Check that any element has the pending or success or error class
use your function scope to store it in a variable
EDIT : if you want to re-enable selection after the request has been posted, you could use something like this (variant of version #1)
I am trying to write a directive for the jeditable plugin so when it changes the value, it will change also edit the model of the edited element.
So i wrote something like that, JS Fiddle
but i don`t know how to get the object that bound to the object in the list.
JS:
var app = angular.module("app", []);
app.controller('ctrl', function ($scope) {
$scope.lst = [{
id: 1,
name: "item1"
}, {
id: 1,
name: "item1"
}, {
id: 2,
name: "item2"
}, {
id: 3,
name: "item3"
}, {
id: 3,
name: "item3"
}];
});
app.directive('uiEditable', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.editable("/echo/json/", {
onblur: 'submit',
onsubmit: function (response, settings) {
//here i need to update the model
}
});
}
};
});
This uses ngModel to update back to the model. (so don't forget ng-model on element)
app.directive('uiEditable', function () {
return {
restrict: 'A',
require: '?ngModel',
link: function (scope, element, attrs, ngModel) {
if (!ngModel) return; // do nothing if no ng-model
element.editable(function (val) {
var tVal = $.trim(val);
if (ngModel.$viewValue !== tVal)
scope.$apply(function () { return ngModel.$setViewValue(tVal); });
return tVal;
});
}
};
});
Why are you using the jeditable plugin? This plugin seems to only duplicate in jQuery what you could already do in angular using ng-model alone and no plugin required.
If you just want to create text which can be edited in place like jEditable does, instead of creating a custom directive simply using ng-submit, ng-click, ng-hide and ng-model. Here's a rough example.
The view:
<form ng-submit="submit()">
<div ng-hide="showEdit"
ng-click="showEdit = true">
{{foo.bar}}
</div>
<div>
<input type="text"
ng-show="showEdit"
ng-model="foo.bar" />
</div>
<a href="#" ng-show="showEdit"
ng-click="submit();">done</a>
</form>
And the controller:
app.controller('myCtrl', function($scope) {
$scope.foo = {
bar: 'some text'
};
$scope.showEdit = false;
$scope.submit = function() {
// hide the edit field
$scope.showEdit = false;
// submit form
console.log('submit form');
}
});
Pass your item in in an isolated scope:
app.directive('uiEditable', function(){
return {
restrict: 'A',
scope: {
item: '='
},
link: function(scope, element, attrs){
element.editable("/echo/json/", {
onblur: 'submit',
onsubmit: function(response, settings){
alert(scope.item);
}
});
}
};
});
'scope.item' will now give you a reference to the item inside your directive.