Dependent filters JS - javascript

I set up dependent filters mFilter (from the mSearch2 Modx component).
There is a script that works fine, provided that the product card has the option brand (Ford) and model (Ford Galaxy). That is, the name of the model - contains the brand
img1
When selecting a specific brand, select appears and option works fine
I have a large database of products and there is no way to change it (change the name of the model to make brand + model)
Question: How to create a condition that checks if there is a model (Galaxy) in the admin panel in the product options for a given brand (for example, Ford)?
img2
Sorry for my English, I hope my question is clear)
<script>
var modelFilter = {
// Our selectors
options: {
marka: '#mse2_tv\\|marka',
model: '#mse2_tv\\|model',
},
// Initializing the function
initialize: function() {
$this = this;
// We get the elements we need and save them as object properties
this.marka = $(this.options['marka']);
this.model = $(this.options['model']);
// We look into parameters of the address line in search of the chosen brand
var params = mSearch2.Hash.get();
// If there is no such brand there - we turn off models
if (params['marka'] == undefined) {
$this.disableModel();
}
// If there is such brand there - we turn on models
else {
$this.enableModel();
}
// We add an operator for brand change
this.marka.find('select').on('change', function() {
// If something is selected, we turn on models
if ($(this).val() != '') {
// We switch model to the first point 'Select from the list'
$this.model.find('option:first').attr('selected', true);
// Then we activate block
$this.enableModel();
}
// If nothing is selected, we turn off models
else {
$this.disableModel();
}
})
},
// Turning off models function
disableModel: function() {
// We look for all fields witn an unempty value
$this.model.find('option[value!=""]').attr('selected', false).attr('disabled', true);
// Then we hide the whole block
$this.model.hide();
},
// Turning on models function
enableModel: function() {
// We get the car brand
var marka = this.marka.find(':selected').text().replace(/\(.*?\)$/, '').replace(/\s+$/, '');
var re = new RegExp('^' + marka);
// Then we go through all models and check their names
$this.model.find('option').each(function() {
var $this = $(this);
// If the name does not fit, model should be turned off
if (!$this.text().match(re) && $this.prop('value') != '') {
$this.attr('disabled', true);
$this.hide();
}
// If it doesm model should be turned on
else {
$this.attr('disabled', false);
$this.show();
}
});
// Then we show the whole block witn models
$this.model.show();
},
}
// Script begins to work when the document is fully downloaded
$(document).ready(function() {
// And if on the page there are filters
if ($('#mse2_mfilter').length > 0) {
modelFilter.initialize();
}
});
</script>

Related

How to display certain photos based on dropdown menu in mobile?

In my job, (I'm just a student worker, nothing major), my boss wants me to figure out a way to display photos on our website. Here's the catch:
My questions are:
is there a better way to go about this? Am I complicating things?
(I considered using a backend database to store the URLs so it would be easy to add/remove from the dropdown menu options, but that's proved to be difficult to figure out)
if this is a good way, how do I make it work on mobile?
$(function() {
// WHEN THE BUILDING CHANGES
$('#buildings').on('change', function() {
// set val equal to BUILDING VALUE
var val = $(this).val();
// set room = ROOMS
var room = $('#room');
// if it's the BSB, show the wings - else hide them.
if (val == "BSB") {
$('#wings').show();
// Change the room numbers based on selected Wing
$('#wings').on('change', function() {
val = $(this).val();
room.find('option').not(':first').hide();
$('option', room).filter(function() {
if ($(this).attr('data-group') == val) {
$(this).show();
}
});
room.val(0);
});
$('#wings').trigger('change');
// must not be the BSB
} else {
$('#wings').hide();
// select room based on Building
room.find('option').not(':first').hide();
$('option', room).filter(function() {
if ($(this).attr('data-group') == val) {
$(this).show();
}
});
room.val(0);
}
});
$('#buildings').trigger('change');
});
function setImage(select){
var image = document.getElementsByName("image-swap")[0];
image.src = select.options[select.selectedIndex].value;
}
function resetImage(){
var image = document.getElementsByName("image-swap")[0];
image.src = "";
}
CLICK HERE FOR THE JSFIDDLE OF MY CODE

Dynamic dropdowns filtering options with jquery

I am trying to filter one dropdown from the selection of another in a Rails 4 app with jquery. As of now, I have:
$(document).ready(function(){
$('#task_id').change(function (){
var subtasks = $('#subtask_id').html(); //works
var tasks = $(this).find(:selected).text(); //works
var options = $(subtasks).filter("optgroup[label ='#{task}']").html(); // returns undefined in console.log
if(options != '')
$('#subtask_id').html(options);
else
$('#subtask_id').empty();
});
});
The task list is a regular collection_select and the subtask list is a grouped_collection_select. Both which work as expected. The problem is that even with this code listed above I can't get the correct subtasks to display for the selected task.
NOTE: I also tried var tasks=$(this).find(:selected).val() that return the correct number but the options filtering still didn't work.
Try something like this instead (untested but should work).
$(function () {
var $parent = $('#task_id'),
$child = $('#subtask_id'),
$cloned = $child.clone().css('display', 'none');
function getParentOption() {
return $parent.find('option:selected');
}
function updateChildOptions($options) {
$child.empty();
$child.append($options);
}
$parent.change(function (e) {
var $option = getParentOption();
var label = $option.prop('value'); // could use $option.text() instead for your case
var $options = $cloned.find('optgroup[label="' + label + '"]');
updateChildOptions($options);
});
});

How to handle different content depending on selected element in the same sidebar

Imaging that we have animals table. Each row describes one animal, for example: ID, NAME, TYPE.
Depending on the selected row type, I want show is the sidebar content related to that animal and some user actions.
Content is completely different, it pulls from data from different APIs.
But the sidebar placed always in the same position, same size and styles.
Maybe I'll have common actions for each controller, like -> close sidebar.
If sidebar already opened and user switch to another one, sidebar should change immediately.
How should I design such login with angular ?
I got an idea to define one directive in html for sidebar. And set listener for selected row, after that compile dynamically sidebar directive for selected row, and insert into parent (main) sidebar.
Probably also I need to handle destroy of previous one.
I appreciate if anyone can tell is I'm going the right way... or should I change something ?
function dtSidebarDirective($compile, $mdUtil, $mdSidenav, $log, mxRegistry) {
return {
restrict: 'E',
templateUrl: 'app/components/sidebar/sidebar.html',
controller: function($scope) {
// used to replace sidebar data on the fly without recompile
$scope.refresh = function() { }
$scope.close = function(ev) {
$mdSidenav('right').close()
}
},
scope: true,
link: link
};
function link(scope, element) {
// used to detect switching between the same type of elements
var _activeType;
var _childDirective;
var _childScope;
var _childElement;
var _toggle = $mdUtil.debounce(function() {
$mdSidenav('right')
.toggle()
.then(function() {
scope.isOpen = $mdSidenav('right').isOpen();
$log.debug('toggle right is done');
});
});
var _init = function(type, data) {
// by default open diagram sidebar
switch(type) {
case 'shape':
_childDirective = $compile('<dt-dog-sidebar></dt-dog-sidebar>');
break;
case 'text':
_childDirective = $compile('<dt-cat-sidebar></dt-cat-sidebar>');
break;
default:
_childDirective = $compile('<dt-animal-sidebar></dt-diagram-sidebar>');
}
// initialize child sidebar : element & scope
_activeType = type;
_childScope = scope.$new();
_childScope.data = data;
_childElement = _childDirective(_childScope);
element.find('md-sidenav').append(_childElement);
};
var _isInitialized = function(type) {
var isDefined = angular.isDefined(_childDirective);
return type ? _activeType == type && isDefined : isDefined;
};
var _destroy = function() {
if(_isInitialized()) {
_childScope.$destroy();
_childElement.empty();
_childElement.remove();
}
};
function showSidebar(ev, type, data) {
// lets figure out does we open the same kind of sidebar
if(_isInitialized(type)) {
_childScope.data = data;
_childScope.refresh();
return;
}
// destroy since we gonna replace with new sidebar
_destroy();
_init(type, data);
}
function toggle() {
update();
_toggle();
}
function update(ev) {
// detect which sidebar should be shown now
}
scope.$on('sidebar:toggle', toggle);
scope.$on('sidebar:show', showSidebar);
scope.$on('sidebar:update', update);
}
I manage to get it work with recompiling each time I need to should different sidebar or call refresh of children scope.

Reusing a modal template

On my current project, there are starting to be a few views that are modal views that are being used to delete items on the site. They are currently generic in that it's just a text description of the item they are deleting. Maybe in the future there will be an icon or a short description as well. There are now tasks to have that functionality to delete other stuff on our site. I'm new to the web, MVC, asp.net, etc, and what I want to know is if it's better to reuse our current modal view somehow, and pass in the objects we need to show in the view. Because the view needs to send the url back to the server on which items to delete, that part of code would need to be different for the view as well. Here is some of the stuff in our view along with a .cshtml template that's pretty generic that I didn't include.
Views.DeleteGiftModal = (function () {
return Backbone.View.extend({
template: Templates["template-gift-delete-modal"],
tagName: 'div',
initialize: function (options) {
$(window).bind("disposeModal", _.bind(this.disposeModal, this));
_.bindAll(this, "showDialog", "disposeModal", "displayResults");
this.eventAggregator = options.eventAggregator;
this.itemsToDelete = options.model;
this.errors = {};
this.render();
return this;
},
events: {
"click #delete-btn": "deleteItems",
"click #ok-btn": "disposeModal",
"click #cancel-btn": "disposeModal"
},
disposeModal: function (event, refresh) {
this.$el.modal("hide");
if (event != null && event.currentTarget != null && event.currentTarget.id == 'ok-btn')
refresh = true;
this.trigger("modalClosed", refresh);
this.remove();
this.unbind();
},
showDialog: function () {
this.$el.modal("show");
},
deleteItems: function () {
var self = this;
var element = this.$el;
var numberGifts = this.getKeys(this.itemsToDelete).length;
this.results = [];
var hasError = false;
element.find("#actions").hide();
element.find("#ok-actions").show();
$.each(this.itemsToDelete, function(i, v) {
// tell model to go away
var gift = new Gift({ id: i });
gift.destroy({
success: function (model, response) {
self.results.push({ id: model.id, response: response });
numberGifts--;
if (numberGifts <= 0) {
if (!hasError) {
self.disposeModal(null, true);
} else {
self.displayResults();
}
}
}
});
});
},
displayResults: function () {
var element = this.$el;
$.each(this.results, function(i, v) {
// to do check response for error message
var list = element.find("#delete-item-" + v.id);
if (v.response.message == "Deleted") {
list.append(" - <span align='right' style='color: green'>Deleted</span>");
} else {
hasError = true;
list.append(" - <span align='right' style='color: red'>" + v.response.message + "</span>");
}
});
},
render: function () {
this.$el.append(this.template);
this.$el.find("#ok-actions").hide();
// show list of item names
var list = this.$el.find("#items-to-delete-list");
$.each(this.itemsToDelete, function (i, v) {
$("<li id='delete-item-" + i + "'>" + v.name + "</li>").appendTo(list);
});
this.$el.attr('id', 'delete-gift-dialog');
return this;
}
});
})();
As I am looking through the code, and this being my first real project, it seems like a lot of things that could be quite similar, like deleting a Gift, deleting a Toy, etc have different Controllers for each (GiftController, ToyController), and hit different URLs. So currently things are all in their own class like that. I was wondering if that's the more standard way to approach these types of problems as well with views. Thanks in advance!
The app we're developing at work had a similar issue. We're using Backbone too so I can completely relate to this. What I ended up doing is have a sort of ModalBuilder that builds a form in a modal for you and binds events on the form elements for submit. The initialization of it could look like this:
new ModalBuilder({
form: [
{
tag: 'select[name="id"]',
options: [
{ name: 'Item 1', id: 12 },
{ name: 'Item 2', id: 32 }
]
},
{
tag: 'input[type="submit"]',
value: 'Delete'
}
],
events: function(){
$('input[type="submit"]').on('click', function(){
// Delete via ajax
})
}
})
What we do is we have different templates for every form element, inputfields and textareas and so on and we reuse it all over the place. ModalBuilder takes these arguments and builds a form
Also for certain cases it might be better to render the form server-side and deliver it to your modal via ajax. You have to weigh what makes your app more performant I suppose.

Zombie views and events in Backbone marionette layout... Have I got them?

I think I might have a problem with zombie views in my Backbone Marionette app.
How can I check for unclosed views and memory leaks? I'm using the illuminations-for-developers.com add-on for Firefox and as I move around my application I see over 1000 views piling up in the 'widgets' illuminations tab - and when I inspect the HTML for them the majority are not in the DOM. Are these zombied views?
Have added the code I'm using below to get peoples opinion on if I'm attacking the problem the right way.
I'm trying to build a UI similar to the Facebook multiple friend selector dialog (see pic).
I have a layout with two collection views, one populated with a list of users, and an empty one in which the selected users are added to.
I want to use this layout in multiple areas of my app. So I have built a controller object that handles initializing it and loading the data for the collections, and then I initialize it and show it in another region whenever it is required.
Would appreciate tips on how to go about this, thanks.
Codez:
MyApp.UserFilterController
MyApp.UserFilterController = (function(){
var UserFilterController = {};
var selectedUsersCol;
var userFilterColView;
var selectedUsersColView;
var usersCol;
UserFilterController.initialize = function ( callback, excludeUsers ) {
// make a query...
// exclude the users...
var usersQ = new Parse.Query(Parse.User);
// just users with email addresses
usersQ.exists('email');
usersQ.exists('name');
usersQ.limit(1000);
usersQ.ascending('name');
usersQ.notContainedIn('objectId',excludeUsers);
usersCol = usersQ.collection();
// tell it where to render... append to the body give it an element?
userFilterColView = new MyApp.UserFilterUserCollectionView({
collection:usersCol
});
usersCol.fetch({
success:function (col) {
console.log("users collection fetched", col.length);
},
error:function () {
console.log("error fetching users collection");
}
});
$('#subpage-header').text("Users Selection");
// empty collection to hold the selected users
selectedUsersCol = new MyApp.Users();
// view to show the selected users
selectedUsersColView = new MyApp.SelectedUserCollectionView({
collection:selectedUsersCol
});
_.extend(selectedUsersCol, newBackboneAddMethod());
MyApp.userFilterLayout = new MyApp.UserFilterLayout();
MyApp.slideUp.content.show(MyApp.userFilterLayout);
MyApp.userFilterLayout.selectedusers.show(selectedUsersColView);
MyApp.userFilterLayout.allusers.show(userFilterColView);
//When user clicks on user in all users then its added to selected users
userFilterColView.on("itemview:clicked", function(childView, model){
console.log(model);
selectedUsersCol.add(model);
});
userFilterColView.on("collection:rendered", function(childView, model){
console.log('its rendered');
});
//When user clicks on selected user then it is removed from the collection
selectedUsersColView.on("itemview:clicked", function(childView, model){
console.log(model);
console.log(model.id);
selectedUsersCol.remove(model);
});
MyApp.App.vent.bind("slideUp:send",function(){
console.log("send button has been clicked. attempting call back")
callback(selectedUsersCol);
});
//unbinds the trigger above when view is being closed
userFilterColView.on('collection:before:close', function (){
MyApp.App.vent.unbind("slideUp:send");
console.log('colView before:close')
});
};
UserFilterController.removeUser = function ( user ) {
//console.log("you asked to remove", usersArray.length, 'users');
selectedUsersCol.remove(user);
usersCol.remove(user);
};
UserFilterController.generateListview = function ( user ) {
userFilterColView.$el.listview();
};
UserFilterController.resetSelected = function (user) {
selectedUsersCol.reset();
};
UserFilterController.cleanup = function () {
console.log("its closing");
//selectedUsersColView.unbindAll();
// selectedUsersColView.close();
userFilterColView.close();
// userFilterLayout.unbindAll();
// MyApp.userFilterLayout.close();
// MyApp.slideUp.content.close();
// MyApp.slideUp.close();
};
return UserFilterController;
}());
MyApp.EventDisplayLayout
MyApp.EventDisplayLayout = Backbone.Marionette.Layout.extend({
template: '#event-display-layout',
id: "EventDisplayLayout",
events: {
'click #invite': 'showUserFilter'
},
// User clicked on 'invite' button
showUserFilter: function () {
$.mobile.changePage($('#subpage'), {changeHash: false,transition: 'slideup'});
MyApp.UserFilterController.generateListview();
}
}
MyApp.showEventDisplay
MyApp.showEventDisplay = function (event) {
var eventDisplayLayout = new MyApp.EventDisplayLayout({});
MyApp.App.mainRegion.show(eventDisplayLayout);
var Invitees = event.get("invitees");
var excludeIds = [];
_.each(Invitees,function(invitee){
excludeIds.push(invitee.id);
});
MyApp.UserFilterController.initialize(function (selectUsersCol){
console.log("In call back: ",selectUsersCol);
},excludeIds);
};
MyApp.SlideUpPageLayout
// The generic layout used for modal panel sliding up from bottom of page.
MyApp.SlideUpPageLayout = Backbone.Marionette.Layout.extend({
el: '#subpage',
//template: '#homepage-temp',
regions: {
header: '.header',
content: '.content'
},
events:{
'click .send':'slideUpSend',
'click .cancel':'slideUpCancel'
},
onShow: function () {
console.log("SlideUpPage onShow");
this.$el.trigger('create');
},
initialize: function () {
// make user collection...
},
slideUpSend: function () {
console.log("send button has been pressed");
MyApp.App.vent.trigger('slideUp:send');
$.mobile.changePage($('.type-home'),{transition: 'slideup',reverse:true});
},
slideUpCancel: function () {
// MyApp.App.vent.trigger('slideUp:cancel');
$.mobile.changePage($('.type-home'),{transition: 'slideup',reverse:true});
}
});
MyApp.UserFilterLayout
// The layout used for the user filter panel sliding up from bottom of page.
MyApp.UserFilterLayout = Backbone.Marionette.Layout.extend({
template: '#userfilterlayout',
//template: '#homepage-temp',
regions: {
selectedusers: '.selectedusers',
allusers: '.allusers'
},
onShow: function () {
console.log("userfilterlayout onShow");
this.$el.trigger('create');
}
});

Categories