vuejs computed property for loop wont increment - for-loop
I have the following elements in my data property
templateArray: [{"id":"7","itemId":"17520","itemName":"Arrow Bounce","thumbName":"ARROWBOUNCE","dateAdded":"2016-05-20 16:33:42","renderTime":"30","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/ArrowBounce-Scott\/arrowBounce.aep","stillImageLocation":"2.66","categoryArray":[],"keywordArray":["LensFlare"]},{"id":"11","itemId":"38752","itemName":"Jitter Zoom Flash","thumbName":"JITTERZOOMFLASH","dateAdded":"2016-05-23 13:49:03","renderTime":"45","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/JitterZoomFlash-Scott\/JitterZoomFlash.aep","stillImageLocation":"2.66","categoryArray":["Sports"],"keywordArray":["Snow","Sparkles"]},{"id":"12","itemId":"12737","itemName":"Cloth Drop","thumbName":"CLOTHDROP","dateAdded":"2016-05-23 14:11:42","renderTime":"30","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/ClothDrop-Scott\/cloth drop.aep","stillImageLocation":"2.66","categoryArray":[],"keywordArray":[]},{"id":"15","itemId":"73076","itemName":"Colorful Trans","thumbName":"COLORFULIMAGETRANS","dateAdded":"2016-05-27 10:16:56","renderTime":"30","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/ColorfulImageTrans-Scott\/ColorfulImageTrans.aep","stillImageLocation":"12.90","categoryArray":[],"keywordArray":["Water","Sparkles"]},{"id":"16","itemId":"18488","itemName":"Convex ½ Circle","thumbName":"CONVEXHALFCIRCLE","dateAdded":"2016-05-27 10:38:20","renderTime":"30","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/convexHalfCircle-Scott\/convex half circle.aep","stillImageLocation":"2.66","categoryArray":[],"keywordArray":[]},{"id":"17","itemId":"67039","itemName":"Flag Swap","thumbName":"FLAGBACKSWAP","dateAdded":"2016-06-01 15:34:22","renderTime":"30","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/FlagBackSwap-Scott\/FlagBackSwap.aep","stillImageLocation":"5.83","categoryArray":[],"keywordArray":[]},{"id":"31","itemId":"70006","itemName":"Flag Raise","thumbName":"FLAGRAISE","dateAdded":"2016-06-03 11:13:37","renderTime":"60","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/FlagRaise-Scott\/flag.aep","stillImageLocation":"2.66","categoryArray":[],"keywordArray":[]},{"id":"32","itemId":"58759","itemName":"Logo Dust Poof","thumbName":"LOGODUSTPOOF","dateAdded":"2016-06-03 11:25:34","renderTime":"30","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/LogoDustPoof-Scott\/LogoDustPoof.aep","stillImageLocation":"6.23","categoryArray":[],"keywordArray":[]},{"id":"33","itemId":"58967","itemName":"Flag Wave (Loop)","thumbName":"FLAGWAVE","dateAdded":"2016-06-03 11:35:49","renderTime":"75","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/FlagWave-Scott\/FlagWave.aep","stillImageLocation":"2.66","categoryArray":[],"keywordArray":[]},{"id":"34","itemId":"65288","itemName":"Logo Splash One","thumbName":"LOGOSPLASHONE","dateAdded":"2016-06-03 15:34:19","renderTime":"45","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/LogoSplashOne-Scott\/LogoSplashOne.aep","stillImageLocation":"2.70","categoryArray":[],"keywordArray":[]},{"id":"35","itemId":"91246","itemName":"Metal Sparks","thumbName":"METALSPARKS","dateAdded":"2016-06-06 10:58:29","renderTime":"60","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/MetalSparks-Scott\/MetalSparks.aep","stillImageLocation":"4.63","categoryArray":[],"keywordArray":[]},{"id":"36","itemId":"57489","itemName":"Middle Stripe","thumbName":"MIDDLESTRIPEABA","dateAdded":"2016-06-06 12:25:41","renderTime":"60","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/MiddleStripe-Scott\/middleStripeABA.aep","stillImageLocation":"6.80","categoryArray":[],"keywordArray":[]},{"id":"37","itemId":"38402","itemName":"Water One","thumbName":"WATERONE","dateAdded":"2016-06-07 09:10:32","renderTime":"60","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/waterOne-Scott\/waterOne.aep","stillImageLocation":"8.83","categoryArray":[],"keywordArray":[]},{"id":"39","itemId":"81031","itemName":"Oval Text Flip","thumbName":"OVALTEXTFLIP","dateAdded":"2016-05-07 09:10:32","renderTime":"150","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/OvalTextFlip-Scott\/OvalTextFlip.aep","stillImageLocation":"2.66","categoryArray":[],"keywordArray":[]},{"id":"40","itemId":"55143","itemName":"Close Up Text","thumbName":"CLOSEUPTEXT","dateAdded":"2016-07-05 09:10:32","renderTime":"85","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/CloseUpText-Scott\/CloseUpText\/CloseUpText.aep","stillImageLocation":"9.03","categoryArray":[],"keywordArray":[]},{"id":"41","itemId":"54335","itemName":"Electric Text Spin","thumbName":"ELECTRICTEXTSPIN","dateAdded":"2016-07-13 09:10:32","renderTime":"60","tested":"1","projectPath":"O:\/Projects\/Generics\/CreativeEngine\/2016\/ElectricTextSpin-Scott\/ElectricTextSpin\/ElectricTextSpin.aep","stillImageLocation":"1.47","categoryArray":[],"keywordArray":[]},{"id":"42","itemId":"23761","itemName":"Digital Glitch","thumbName":"DIGITALGLITCH","dateAdded":"2016-09-19 09:10:32","renderTime":"60","tested":"1","projectPath":"O:\/Projects\/Generics\/CreativeEngine\/2016\/DigitalGlitch-Scott\/DigitalGlitch.aep","stillImageLocation":"3.43","categoryArray":["Retail"],"keywordArray":[]},{"id":"43","itemId":"56465","itemName":"Takeover","thumbName":"TAKEOVER","dateAdded":"2016-09-30 14:10:32","renderTime":"80","tested":"1","projectPath":"O:\/Projects\/Generics\/CreativeEngine\/2016\/TakeOver-Scott\/TakeoverProject\/takeoverproject.aep","stillImageLocation":"2.66","categoryArray":[],"keywordArray":[]},{"id":"44","itemId":"17127","itemName":"Fire One","thumbName":"FIREONE","dateAdded":"2016-11-04 14:10:32","renderTime":"25","tested":"1","projectPath":"O:\/Projects\/Generics\/CreativeEngine\/2016\/FireOne-Scott\/FireOne.aep","stillImageLocation":"2.66","categoryArray":[],"keywordArray":[]},{"id":"53","itemId":"61617","itemName":"City Spin","thumbName":"CITYSPIN","dateAdded":"2016-11-09 14:17:15","renderTime":"45","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2016\/CitySpin-Scott\/cityspin.aep","stillImageLocation":"8.933","categoryArray":["Church"],"keywordArray":[]},{"id":"56","itemId":"15528","itemName":"Magic Colors","thumbName":"MAGICCOLORS","dateAdded":"2016-11-10 13:10:26","renderTime":"30","tested":"1","projectPath":"O:\/Projects\/Generics\/CreativeEngine\/2016\/MagicColors-Scott\/MagicColors.aep","stillImageLocation":"3.966","categoryArray":[],"keywordArray":[]},{"id":"61","itemId":"59239","itemName":"Quick and Simple","thumbName":"QUICKNSIMPLE","dateAdded":"2016-11-14 11:42:09","renderTime":"15","tested":"1","projectPath":"O:\/Projects\/Generics\/CreativeEngine\/2016\/QuickNSimple-Scott\/QuickNSimple.aep","stillImageLocation":"2.033","categoryArray":[],"keywordArray":[]},{"id":"62","itemId":"82460","itemName":"Fast Blast","thumbName":"FASTBLAST","dateAdded":"2016-11-22 10:24:48","renderTime":"30","tested":"1","projectPath":"O:\/Projects\/Generics\/CreativeEngine\/2016\/FastBlast-Scott\/FastBlast.aep","stillImageLocation":"9.666","categoryArray":[],"keywordArray":[]},{"id":"63","itemId":"83530","itemName":"Tunnel Spin","thumbName":"TUNNELSPIN","dateAdded":"2016-12-02 13:09:06","renderTime":"20","tested":"1","projectPath":"O:\/Projects\/Generics\/CreativeEngine\/2016\/tunnelSpin-Scott\/tunnelSpin.aep","stillImageLocation":"2.9","categoryArray":[],"keywordArray":[]},{"id":"64","itemId":"94148","itemName":"Sparkle Splash","thumbName":"SPARKLESPLASH","dateAdded":"2016-12-20 11:23:26","renderTime":"45","tested":"1","projectPath":"O:\/Projects\/Generics\/CreativeEngine\/2016\/SparkleSplash-Scott\/SparkleSplash.aep","stillImageLocation":"6.1","categoryArray":[],"keywordArray":[]},{"id":"69","itemId":"98640","itemName":"Gold Bling","thumbName":"GOLDBLING","dateAdded":"2017-01-10 08:16:41","renderTime":"30","tested":"1","projectPath":"O:\/Projects\/Generics\/CreativeEngine\/2017\/GoldBling-Joe\/GoldBling.aep","stillImageLocation":"2.66","categoryArray":[],"keywordArray":[]},{"id":"72","itemId":"94169","itemName":"Top Racer","thumbName":"TOPRACER","dateAdded":"2017-02-15 09:46:14","renderTime":"30","tested":"1","projectPath":"O:\/Projects\/Generics\/CreativeEngine\/2017\/TopRacer-Scott\/TopRacer.aep","stillImageLocation":"7.833","categoryArray":[],"keywordArray":[]},{"id":"73","itemId":"55871","itemName":"Desert Sand","thumbName":"DESERTSAND","dateAdded":"2017-02-15 14:04:49","renderTime":"45","tested":"1","projectPath":"O:\/Projects\/Generics\/CreativeEngine\/2017\/DesertSand-Scott\/DesertSand.aep","stillImageLocation":"10.46","categoryArray":[],"keywordArray":[]},{"id":"76","itemId":"18897","itemName":"Electric Storm","thumbName":"ELECTRICSTORM","dateAdded":"2017-02-23 12:43:08","renderTime":"45","tested":"1","projectPath":"O:\/Projects\/Generics\/CreativeEngine\/2017\/ElectricStorm-Scott\/ElectricStorm.aep","stillImageLocation":"4.333","categoryArray":[],"keywordArray":[]},{"id":"78","itemId":"24052","itemName":"Court Smash","thumbName":"COURTSMASH","dateAdded":"2016-06-03 12:03:48","renderTime":"90","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2017\/CourtSmash-Scott\/CourtSmash.aep","stillImageLocation":"5.933","categoryArray":[],"keywordArray":[]},{"id":"81","itemId":"43553","itemName":"Tile Flip","thumbName":"TILEFLIP","dateAdded":"2017-04-25 16:40:41","renderTime":"60","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2017\/TileFlip-Chris\/TileFlip_Final\/TileFlip_Final.aep","stillImageLocation":"5","categoryArray":[],"keywordArray":[]},{"id":"88","itemId":"94677","itemName":"NEON LIGHTS","thumbName":"NEONLIGHTS","dateAdded":"2017-04-28 10:06:23","renderTime":"45","tested":"1","projectPath":"O:\/Projects\/Generics\/CreativeEngine\/2017\/NEONLIGHTS-Joe\/NeonLights.aep","stillImageLocation":"2.53","categoryArray":[],"keywordArray":[]},{"id":"89","itemId":"64305","itemName":"Engine (Loop)","thumbName":"ENGINE","dateAdded":"2017-05-15 11:37:07","renderTime":"60","tested":"1","projectPath":"O:\/Projects\/Generics\/CreativeEngine\/2017\/Engine-Scott\/Engine.aep","stillImageLocation":"4.67","categoryArray":[],"keywordArray":[]},{"id":"90","itemId":"11287","itemName":"Energy Core","thumbName":"ENERGYCORE","dateAdded":"2017-05-22 13:08:40","renderTime":"30","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2017\/EnergyCore-Scott\/EnergyCore.aep","stillImageLocation":"6.73","categoryArray":[],"keywordArray":[]},{"id":"91","itemId":"48745","itemName":"Football Helmet","thumbName":"FOOTBALLHELMET","dateAdded":"2017-07-03 16:09:42","renderTime":"120","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2017\/FootballHelmet-Scott\/FootballHelmet.aep","stillImageLocation":"7","categoryArray":[],"keywordArray":[]},{"id":"92","itemId":"85515","itemName":"Light Shine","thumbName":"LIGHTSHINE","dateAdded":"2017-08-18 14:09:50","renderTime":"30","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2017\/LightShine-Scott\/LightShine.aep","stillImageLocation":"2","categoryArray":[],"keywordArray":[]},{"id":"93","itemId":"61876","itemName":"Baseball Dirt","thumbName":"BASEBALLDIRT","dateAdded":"2017-08-31 10:31:22","renderTime":"40","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2017\/BaseballDirt-Scott\/BaseballDirt.aep","stillImageLocation":"7.27","categoryArray":[],"keywordArray":[]},{"id":"94","itemId":"48066","itemName":"Spooky","thumbName":"SPOOKY","dateAdded":"2017-09-01 13:58:36","renderTime":"15","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2017\/Spooky-Jake\/Spooky.aep","stillImageLocation":"2","categoryArray":["Sports"],"keywordArray":[]},{"id":"95","itemId":"33584","itemName":"Get Loud","thumbName":"GETLOUD","dateAdded":"2017-09-07 11:58:02","renderTime":"45","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2017\/GetLoud-Scott\/GetLoud.aep","stillImageLocation":"1.77","categoryArray":[],"keywordArray":[]},{"id":"96","itemId":"21713","itemName":"STAR BURST","thumbName":"STARBURST","dateAdded":"2017-10-19 18:20:29","renderTime":"15","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2017\/StarBurst-Joe\/StarBurst.aep","stillImageLocation":"0","categoryArray":[],"keywordArray":[]},{"id":"97","itemId":"76554","itemName":"Magic Twirl","thumbName":"MAGICFINAL","dateAdded":"2017-10-26 11:19:52","renderTime":"20","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2017\/Magic-Lillie\/Magic.aep","stillImageLocation":"825","categoryArray":[],"keywordArray":[]},{"id":"98","itemId":"64452","itemName":"Sports Car","thumbName":"SPORTSCAR","dateAdded":"2017-10-27 10:26:32","renderTime":"60","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2017\/SportsCar-Scott\/SportsCar.aep","stillImageLocation":"14.77","categoryArray":[],"keywordArray":[]},{"id":"99","itemId":"15074","itemName":"Ice Logo","thumbName":"ICELOGO","dateAdded":"2017-11-01 11:53:48","renderTime":"45","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2017\/IceLogo-Scott\/IceLogo.aep","stillImageLocation":"9.33","categoryArray":[],"keywordArray":["LensFlare"]},{"id":"100","itemId":"95033","itemName":"Hot Air Balloon","thumbName":"BALLOON","dateAdded":"2017-11-02 08:10:22","renderTime":"10","tested":"1","projectPath":"M:\/Projects\/Generics\/CreativeEngine\/2017\/Balloon-Lillie\/Balloon.aep","stillImageLocation":"567","categoryArray":[],"keywordArray":[]},{"id":"243","itemId":"f0adeb21cfbfc7e1894debeef4cc6e22","itemName":"testingCrap","thumbName":"TESTINGCRAP","dateAdded":"2018-10-08 18:06:48","renderTime":"4","tested":"0","projectPath":"M:\/Projects\/Generics\/uploads\/testLocation","stillImageLocation":"0.13","categoryArray":["Sports","Holiday"],"keywordArray":["LensFlare"]}],
as you can see each template has an in the templateArray each object contains a categoryArray element like this categoryArray: "sports, holidays"
I also have a filteredTemplateArray:[]
selectedCategoriesArray:[],
categories: ["Holiday","Sports","Misc","Automotive","Retail","Financial","Church","Community","Food"],
Heres the font end code for the checkbox
<div class="form-group">
<h5>Categories</h5>
<label v-for="category in categories">
<input v-model="selectedCategories" type="checkbox" :value="category" v-on:click="selectedCategory=category; selectCategory">
{{category}}
</label>
</div>
lastly I have a computed property called selectCategory it looks like this
selectCategory: function(){
if(this.selectedCategories.length!=0){
var templateArray=this.templateArray;
for (var i=0; i<this.selectedCategories.length; i++){
console.log(i);
return this.filteredTemplateArray=templateArray.filter((template)=>{
return template.categoryArray.includes(this.selectedCategories[i]);
})
}
}
}
I also am displaying the template info with this for loop
<div v-cloak v-bind:key="template.itemId + '_' + index" v-for="(template, index) in selectCategory" class="col-md-4">
<div class="card">
<video muted :src="'mysource/'+template.itemId+'/'+template.thumbName+'.mp4'" controls preload="none" controlsList="nodownload nofullscreen" :poster="'mysource/'+template.itemId+'/'+template.thumbName+'.jpg'" loop="loop"></video>
<div class="card-body">
<p class="card-title">{{template.itemName}}</p>
<!--end card-title-->
<p v-show="displayCount==0" class="card-text">Please create a display to customize</p>
<!--end user has no display card-text-->
<p v-show="displayCount>0" class="card-text">Custom Text, Custom Colors, Upload Logo</p>
<!--end user has display card text-->
<p class="card-text">{{template.renderTime}} minutes</p>
Customize
<!--logged in and has display button-->
<a href="#" v-show="loggedIn==false" class="btn btn-primary btn-block" disabled>Customize</a>
<!--not logged in button-->
Create A Display
</div>
<!--end card-body-->
</div>
<!--end card-->
</div>
everytime the user clicks on a category checkbox this function is run. Im trying to filter through the template array and find the items that contain the selected categories. however i always stops at 0 no matter what. When I add more than one item it does not work. I need away to get all the items that contain the selected categories and if selectedCategories is empty set filteredTemplateArray to the templateArray so all the items show up. Any ideas on how to do this?
move the for loop lower in the method as shown. I also created a watcher that watches selectedCategories and when it changes run a method that filters out the duplicates and sets filtered categories back to the original array when the selectedCategories.length==0. This creates a category filter that counts up. for instance if sports and holidays are checked it will show only all items in sports and all items in holidays which seems to work better than counting down or showing the ones that only exist in both. I use app instead of this as its the variable i called my vue instance and because when you get deep into a function this does not always mean the app.
watch: {
selectedCategories(){
this.categoryFilter();
},
sortBy(){
this.sortTemplatesBy();
}
},
methods: {
sortTemplatesBy: function(){
if(this.sortBy == "az") {
this.filteredTemplateArray.sort(function(a,b) {
if(a.itemName > b.itemName) {
return 1;
}
if(a.itemName < b.itemName) {
return -1;
}
return 0;
});
}
if(this.sortBy == "dateAdded") {
this.filteredTemplateArray.sort(function(a,b) {
if(a.dateAdded < b.dateAdded) {
return 1;
}
if(a.dateAdded > b.dateAdded) {
return -1;
}
return 0;
});
}
if(this.sortBy == "renderTime") {
this.filteredTemplateArray.sort(function(a,b) {
return parseInt(a.renderTime) - parseInt(b.renderTime);
});
}
},
categoryFilter: function(){
if(app.selectedCategories.length!=0){
app.filteredTemplateArray=[];
var templateArray = app.templateArray;
for(i=0; i<app.selectedCategories.length; i++){
var filtered=templateArray.filter(function(template){
var currentCategory=app.selectedCategories[i];
console.log("this is current category"+currentCategory+"end currentCategory");
var returnValue=template.categoryArray.includes(currentCategory);
console.log("this is i"+i+"end i");
console.log("this is return value"+returnValue+"end return value");
return returnValue;
});
console.log(filtered);
app.filteredTemplateArray=app.filteredTemplateArray.concat(filtered);
}
var uniqueArray=[];
var allResultsArray=app.filteredTemplateArray;
for(j=0; j<allResultsArray.length; j++){
if(uniqueArray.indexOf(allResultsArray[j]) == -1){
uniqueArray.push(allResultsArray[j])
}
}
app.filteredTemplateArray=uniqueArray;
} else {app.filteredTemplateArray=app.templateArray;}
this.sortTemplatesBy();
}
}
Related
Umbraco Starter Kit sorting blog posts in wrong order
I tried to find the right answer first but had no luck. I am working on a website using the Starter Kit of Umbraco in V7 For some reason, it sorts the blog posts using oldest first, while I want to get the newest posts first in the list view using Partial View Macro 'GetLatestBlogPosts' Here is the code I'm currently using for the Partial View Macro: #using ContentModels = Umbraco.Web.PublishedContentModels; #using Umbraco.Web; #inherits Umbraco.Web.Macros.PartialViewMacroPage #{ var startNodeId = Model.MacroParameters["startNodeId"] != null Model.MacroParameters["startNodeId"] : Model.Content.Id; var numberOfPosts = 3; if (Model.MacroParameters["numberOfPosts"] != null) { int.TryParse((string)Model.MacroParameters["numberOfPosts"], out numberOfPosts); } } #if (startNodeId != null) { #* Get the starting page *# var startNode = Umbraco.TypedContent(startNodeId); //Gets all blogposts to calculate pages var blogposts = startNode.Children.OrderByDescending(x => x.GetPropertyValue("PublicationDate")).ToList(); var pageCount = (int)Math.Ceiling((double)blogposts.Count / (double)numberOfPosts); var page = 1; if (!string.IsNullOrEmpty(Request.QueryString["page"])) { int.TryParse(Request.QueryString["page"], out page); if (page <= 0 || page > pageCount) { page = 1; } } //Gets the blogposts for the current page var pagedBlogposts = blogposts.Skip((page - 1) * numberOfPosts).Take(numberOfPosts).ToList(); if (pagedBlogposts.Count > 0) { <div class="blogposts"> #foreach (ContentModels.Blogpost post in pagedBlogposts) { <a href="#post.Url" class="blogpost"> <div class="blogpost-meta"> <small class="blogpost-date">#post.CreateDate.ToLongDateString()</small> <small class="blogpost-cat"> #Html.Partial("~/Views/Partials/CategoryLinks.cshtml", post.Categories) </small> </div> #if(post.FeaturedImage != null){ <div class="blogpost-image"> <img class="img-responsive" src="#post.FeaturedImage.Url?width=200" alt="#post.PageTitle" style="width: 100%; height: 100%;"/> </div> } <h3 class="blogpost-title">#post.PageTitle</h3> <div class="blogpost-excerpt">#post.Excerpt</div> </a> } </div> } if (blogposts.Count > numberOfPosts) { <div class="pagination"> <nav class="nav-bar nav-bar--center"> #if (page <= 1) { <span class="nav-link nav-link--black nav-link--disabled">Prev</span> } else { <a class="nav-link nav-link--black" href="#(Model.Content.Url + "?page=" + (page - 1))">Prev</a> } #for (int i = 1; i <= pageCount; i++) { <a class="nav-link nav-link--black #(page == i ? "nav-link--active" : null)" href="#(Model.Content.Url + "?page=" + i)">#i</a> } #if (page == pageCount) { <span class="nav-link nav-link--black nav-link--disabled">Next</span> } else { <a class="nav-link nav-link--black" href="#(Model.Content.Url + "?page=" + (page + 1))">Next</a> } </nav> </div> } } I am completely stuck. Tried some things but all I try is going to break the site. Would really appreciate some help here to get this sorted in the desired way. Thanks a lot for some guidance and assistance
As you figured out yourself, you are trying to sort by a non-existing property on your item. I would recommend that you add a property on your blog posts called publishDate or something like that. You can then set this property on each of your posts to indicate when they are 'published'. The reason why you would not want to just use the build in properties (like created date or published date) for something like this, is that if you need to update an old blog post (maybe correcting a typo) the publish date will now be updated when you republish. So simply correcting a typo will now make the old blog post appear as it being the latest blog post. You should of course implement a fallback so if this property isn't set, the publish date will fallback to using the actual latest publish date from the item.
how to validate 2 fields with Minimum/Maximum compare validation in ionic3?
Working on reactive form group which contain 2 fields such as min and max, data is coming form hard-coded array data . when we enter the value on respective field just want to show validation that min value should be greater than max
Hope this will help you create a form as bellow createForm() { this.personalDataForm = new FormGroup({ fieldOne: new FormControl("", [Validators.minLength(5), Validators.maxLength(15)]) // ... }); } add validations to your template <form [formGroup]="personalDataForm"> <ion-row> <label class="lbl-lnu">fieldOne :</label> <input type="text" class="input-lnu" formControlName="fieldOne"> <div class="form-control-feedback" *ngIf="personalDataForm.controls.fieldOne.errors && (personalDataForm.controls.fieldOne.dirty || personalDataForm.controls.fieldOne.touched)"> <p class="error-msg" *ngIf="personalDataForm.controls.fieldOne.errors.minlength">Minimum length is 5</p> <p class="error-msg" *ngIf="personalDataForm.controls.fieldOne.errors.maxlength">Maximun length is 15</p> </div> </div> </ion-row> </form> to fire validation when submit, use bellow function function isValid(): boolean { const valid = this.personalDataForm.valid if (!valid) { // if not valid fire validation Object.keys(this.personalDataForm.controls).forEach(field => { const control = this.personalDataForm.get(field); control.markAsTouched({ onlySelf: true }); }); } return valid; // if form data valid return true, otherwise false }
I want to check at least one value in ng-repeat, if found, then to display <div> class
In my ng-repeat, scored/not scored are there. I want to display <div> class if at least one item in the ng-repeat has "Not Scored"
You should be determining whether or not you are displaying that div inside your controller. Doing it within the ng-repeat would mean you would have logic in your view and that's just not good practice. Here is a simple example on how to accomplish what you're wanting. In your controller: $scope.showDiv = false; $scope.getItems = function () { // fetch items via ajax... for (var i = 0; i < data.items.length; i++) { if (data.items[i].foo == 'Not Scored') { showDiv = true; } } } And on your view: <div ng-show="showDiv"> // do your ng-repeat here </div>
Jquery Accordion Validation Not working when rendering Partial View through $.ajax call
Hi friends,I am working on MVC 4 Razor and I am stuck in a situation where Employee Personal Details form is to be filled in steps(wizard)..for which i used jquery accordion control..for every step i put an accordion..The html in each accordion section is rendered from partial view through ajax call on every click of respective accordion (i.e. <h3></h3> tag).. On page load first/top accordion is active by default. My problem is to restrict the user to click on next accordion until he/she fills the presently active accordion correctly.. Here is my full code: View: #model XXX.ViewModels.PersonalDetailsViewModel #{ ViewBag.Title = "PersonalDetails"; Layout = "~/Views/Shared/Template.cshtml"; } #using (Html.BeginForm("Lifestyle", "Apply", FormMethod.Post, new { id = "personalDetailForm" })) { <div class="centerdiv margin_top20"> <div class="row"> #Html.ValidationSummary(true, "Please Correct the following errors:") </div> <div style="width: 1000px;"> <div id="Personalaccordion" class="acordion_div" style="padding: 10px; float: left;"> <h3 class="acordion_div_h3" onclick="javascript:PersonalModule.GetRenderingView('Apply/GetBasicDetailsView','personalDetailForm','BasicDetailsDiv');"> <p> Basic Details<span id="BasicDetailsDivExp"></span> </p> </h3> <div id="BasicDetailsDiv"> </div> <h3 class="acordion_div_h3" onclick="javascript:PersonalModule.GetRenderingView('Apply/GetPersonalAddressView','personalDetailForm','PersonalAddressDiv');"> <p> Address<span id="PersonalAddressDivExp"></span></p> </h3> <div id="PersonalAddressDiv"> </div> </div> <ul id="conlitue_ul" style="margin-top: 20px;"> <li style="margin-left: 140px;"> <input type="submit" class="compareBtn float_lt" value="Continue Buying >" id="continue" /></li> </ul> </div> </div> } #Scripts.Render("~/bundles/PersonalDetails") <script type="text/javascript"> PersonalModule.GetRenderingView('Apply/GetBasicDetailsView', '', 'BasicDetailsDiv'); </script> My Controller: public ActionResult PersonalDetails(int leadId) { var personalDetailsViewModel = LeadHelper.GetPersonalDetails(leadId); return View(personalDetailsViewModel); } public ActionResult GetBasicDetailsView(PersonalDetailsViewModel personalDetailsViewModel) { if (personalDetailsViewModel.BasicDetails == null) { ModelInitializerHelper.InitilaizeBasicDetailsVModel(personalDetailsViewModel); } ModelInitializerHelper.InitializeBasicLookup(personalDetailsViewModel); return PartialView("Personal/BasicDetails", personalDetailsViewModel); } public ActionResult GetPersonalAddressView(PersonalDetailsViewModel personalDetailsViewModel) { if (personalDetailsViewModel.PersonalAddressDetails == null) { ModelInitializerHelper.IntializePersonalAddressVModel(personalDetailsViewModel); } ModelInitializerHelper.InitializePersonalAddressLookup(personalDetailsViewModel); return PartialView("Personal/PersonalAddress", personalDetailsViewModel); } My JS : var PersonalModule = { GetRenderingView: function (url, formId, containerID) { var applicationurl = ApplicationRoot + '/' + url; var objects = $('#BasicDetailsDivExp , #PersonalAddressDivExp' ); viewDivID = containerID; GetAccordionView(applicationurl, formId, objects, containerID, 'accordion_plus', 'accordion_minus'); } } GetAccordionView: function (url, formId, objects, containerID, accordion_plus, accordion_minus) { var formObjectData = null; if (formId != undefined) { formObjectData = $("#" + formId).serialize(); } var renderView = function (data) { $('#' + containerID).innerHtml = data; } ExpandAccordion(objects, containerID, accordion_plus, accordion_minus); DoServerRequest(url, formObjectData, renderView); } ExpandAccordion: function (objects, spanIconID, accordion_plus, accordion_minus) { var Objects = objects; Objects.removeClass(accordion_minus); Objects.addClass(accordion_plus); $('#' + spanIconID + 'Exp').removeClass(accordion_plus).addClass(accordion_minus); if (Browser.ie7) { Objects.css("margin-top", "-22px"); } } DoServerRequest: function (url, data, funSuccess) { $.ajax({ type: "POST", url: url, data: data, async: false, dataType: "json", success: funSuccess, error: function (errorResponse) { if (errorResponse.readyState == 4 && errorResponse.status == 200) { renderCurrentView(errorResponse.responseText) } else { alert(errorResponse.responseText); } } }); } Please somebody help..I have heard lots of good thing about this forum and this is my first Question...Thanks in advance.. I have removed my jquery validation attempt as it made the code garbage thing Now I dont know what to write and where to write
If you are trying to validate data that has been added to form via Ajax after page load then you will need to use the rules method and add rules for these new elements. Jquery Validate has no way of knowing about them otherwise. Example Once you have loaded your new content via Ajax you need to find each element and add the necessary rules to them. $('#yourDiv').find(".newElements").rules("add", { required: true, messages: { required: "Bacon is required" } }); If you are using unobtrusive validate you may need to add your new elements to that also. See this SO question for more details. Validating the Form To check if the fields are valid, you will need to validate the form on click. This can be done using .validate(). You can then check if the form validated using .valid() Example $('#yourForm').validate(); if(!$('#yourForm').valid()) { alert('Bacon is required'); }
Knockout.js wizard validation on each step
I have managed to create a simple wizard based on an answer given by Niemeyer. This works fine. I want to add validation. I have managed to add a required validion on the field Firstname. Leaving this empty displays an error. But what I could not succeed in is the following: Validate the model in the current step, and have the go next enabled or disabled based whether there are errors. If it is too difficult to enable or disable the next button, that is ok. I can also live without the button disabled when there are errors. As long as the user is prevented to proceed to the next step when there are errors. . My view looks like this: //model is retrieved from server model <script type="text/javascript"> var serverViewModel = #Html.Raw(Json.Encode(Model)); </script> <h2>Test with wizard using Knockout.js</h2> <div data-bind="template: { name: 'currentTmpl', data: currentStep }"></div> <hr/> <button data-bind="click: goPrevious, enable: canGoPrevious">Previous</button> <button data-bind="click: goNext, enable: canGoNext">Next</button> <script id="currentTmpl" type="text/html"> <h2 data-bind="text: name"></h2> <div data-bind="template: { name: getTemplate, data: model }"></div> </script> <script id="nameTmpl" type="text/html"> <fieldset> <legend>Naamgegevens</legend> <p data-bind="css: { error: FirstName.hasError }"> #Html.LabelFor(model => model.FirstName) #Html.TextBoxFor(model => model.FirstName, new { data_bind = "value: FirstName, valueUpdate: 'afterkeydown'"}) <span data-bind='visible: FirstName.hasError, text: FirstName.validationMessage'> </span> </p> #Html.LabelFor(model => model.LastName) #Html.TextBoxFor(model => model.LastName, new { data_bind = "value: LastName" }) </fieldset> </script> <script id="addressTmpl" type="text/html"> <fieldset> <legend>Adresgegevens</legend> #Html.LabelFor(model => model.Address) #Html.TextBoxFor(model => model.Address, new { data_bind = "value: Address" }) #Html.LabelFor(model => model.PostalCode) #Html.TextBoxFor(model => model.PostalCode, new { data_bind = "value: PostalCode" }) #Html.LabelFor(model => model.City) #Html.TextBoxFor(model => model.City, new { data_bind = "value: City" }) </fieldset> </script> <script id="confirmTmpl" type="text/html"> <fieldset> <legend>Naamgegevens</legend> #Html.LabelFor(model => model.FirstName) <b><span data-bind="text:NameModel.FirstName"></span></b> <br/> #Html.LabelFor(model => model.LastName) <b><span data-bind="text:NameModel.LastName"></span></b> </fieldset> <fieldset> <legend>Adresgegevens</legend> #Html.LabelFor(model => model.Address) <b><span data-bind="text:AddressModel.Address"></span></b> <br/> #Html.LabelFor(model => model.PostalCode) <b><span data-bind="text:AddressModel.PostalCode"></span></b> <br/> #Html.LabelFor(model => model.City) <b><span data-bind="text:AddressModel.City"></span></b> </fieldset> <button data-bind="click: confirm">Confirm</button> </script> <script type='text/javascript'> $(function() { if (typeof(ViewModel) != "undefined") { ko.applyBindings(new ViewModel(serverViewModel)); } else { alert("Wizard not defined!"); } }); </script> The knockout.js implementation looks like this: function Step(id, name, template, model) { var self = this; self.id = id; self.name = ko.observable(name); self.template = template; self.model = ko.observable(model); self.getTemplate = function() { return self.template; }; } function ViewModel(model) { var self = this; self.nameModel = new NameModel(model); self.addressModel = new AddressModel(model); self.stepModels = ko.observableArray([ new Step(1, "Step1", "nameTmpl", self.nameModel), new Step(2, "Step2", "addressTmpl", self.addressModel), new Step(3, "Confirmation", "confirmTmpl", {NameModel: self.nameModel, AddressModel:self.addressModel})]); self.currentStep = ko.observable(self.stepModels()[0]); self.currentIndex = ko.dependentObservable(function() { return self.stepModels.indexOf(self.currentStep()); }); self.getTemplate = function(data) { return self.currentStep().template(); }; self.canGoNext = ko.dependentObservable(function () { return self.currentIndex() < self.stepModels().length - 1; }); self.goNext = function() { if (self.canGoNext()) { self.currentStep(self.stepModels()[self.currentIndex() + 1]); } }; self.canGoPrevious = ko.dependentObservable(function() { return self.currentIndex() > 0; }); self.goPrevious = function() { if (self.canGoPrevious()) { self.currentStep(self.stepModels()[self.currentIndex() - 1]); } }; } NameModel = function (model) { var self = this; //Observables self.FirstName = ko.observable(model.FirstName).extend({ required: "Please enter a first name" });; self.LastName = ko.observable(model.LastName); return self; }; AddressModel = function(model) { var self = this; //Observables self.Address = ko.observable(model.Address); self.PostalCode = ko.observable(model.PostalCode); self.City = ko.observable(model.City); return self; }; And I have added an extender for the required validation as used in the field Firstname: ko.extenders.required = function(target, overrideMessage) { //add some sub-observables to our observable target.hasError = ko.observable(); target.validationMessage = ko.observable(); //define a function to do validation function validate(newValue) { target.hasError(newValue ? false : true); target.validationMessage(newValue ? "" : overrideMessage || "This field is required"); } //initial validation validate(target()); //validate whenever the value changes target.subscribe(validate); //return the original observable return target; };
This was a tricky one, but I'll offer a couple of solutions for you... If you simply want to prevent the Next button from proceeding with an invalid model state, then the easiest solution I found is to start by adding a class to each of the <span> tags that are used for displaying the validation messages: <span class="validationMessage" data-bind='visible: FirstName.hasError, text: FirstName.validationMessage'> (odd formatting to prevent horizontal scrolling) Next, in the goNext function, change the code to include a check for whether or not any of the validation messages are visible, like this: self.goNext = function() { if ( (self.currentIndex() < self.stepModels().length - 1) && ($('.validationMessage:visible').length <= 0) ) { self.currentStep(self.stepModels()[self.currentIndex() + 1]); } }; Now, you may be asking "why not put that functionality in the canGoNext dependent observable?", and the answer is that calling that function wasn't working like one might thing it would. Because canGoNext is a dependentObservable, its value is computed any time the model that it's a member of changes. However, if its model hasn't changed, canGoNext simply returns the last calculated value, i.e. the model hasn't changed, so why recalculate it? This wasn't vital when only checking whether or not there were more steps remaining, but when I tried to include validation in that function, this came into play. Why? Well, changing First Name, for example, updates the NameModel it belongs to, but in the ViewModel, self.nameModel is not set as an observable, so despite the change in the NameModel, self.nameModel is still the same. Thus, the ViewModel hasn't changed, so there's no reason to recompute canGoNext. The end result is that canGoNext always sees the form as valid because it's always checking self.nameModel, which never changes. Confusing, I know, so let me throw a bit more code at you... Here's the beginning of the ViewModel, I ended up with: function ViewModel(model) { var self = this; self.nameModel = ko.observable(new NameModel(model)); self.addressModel = ko.observable(new AddressModel(model)); ... As I mentioned, the models need to be observable to know what's happening to them. Now the changes to the goNext and goPrevious methods will work without making those models observable, but to get the true real-time validation you're looking for, where the buttons are disabled when the form is invalid, making the models observable is necessary. And while I ended up keeping the canGoNext and canGoPrevious functions, I didn't use them for validation. I'll explain that in a bit. First, though, here's the function I added to ViewModel for validation: self.modelIsValid = ko.computed(function() { var isOK = true; var theCurrentIndex = self.currentIndex(); switch(theCurrentIndex) { case 0: isOK = (!self.nameModel().FirstName.hasError() && !self.nameModel().LastName.hasError()); break; case 1: isOK = (!self.addressModel().Address.hasError() && !self.addressModel().PostalCode.hasError() && !self.addressModel().City.hasError()); break; default: break; }; return isOK; }); [Yeah, I know... this function couples the ViewModel to the NameModel and AddressModel classes even more than simply referencing an instance of each of those classes, but for now, so be it.] And here's how I bound this function in the HTML: <button data-bind="click: goPrevious, visible: canGoPrevious, enable: modelIsValid">Previous</button> <button data-bind="click: goNext, visible: canGoNext, enable: modelIsValid">Next</button> Notice that I changed canGoNext and canGoPrevious so each is bound to its button's visible attribute, and I bound the modelIsValid function to the enable attribute. The canGoNext and canGoPrevious functions are just as you provided them -- no changes there. One result of these binding changes is that the Previous button is not visible on the Name step, and the Next button is not visible on the Confirm step. In addition, when validation is in place on all of the data properties and their associated form fields, deleting a value from any field instantly disables the Next and/or Previous buttons. Whew, that's a lot to explain! I may have left something out, but here's the link to the fiddle I used to get this working: http://jsfiddle.net/jimmym715/MK39r/ I'm sure that there's more work to do and more hurdles to cross before you're done with this, but hopefully this answer and explanation helps.