如何移除Spotify API返回items数组中的空对象行
Spotify API播放列表自动补全:移除空对象解决报错
问题背景
基于Spotify API实现播放列表自动补全功能,已成功建立连接并获取API响应,但返回的items数组中偶尔存在空对象,导致程序抛出**Cannot read properties of null (reading 'name')**错误。即使单独校验name属性,仍会出现images或owner相关的同类报错,需要在map处理结果前直接移除这些空对象。
已配置的权限范围:
$options = [ 'scope' => [ 'user-read-email', 'user-read-private', 'user-read-recently-played', 'user-library-modify', 'playlist-read-private', 'playlist-read-collaborative', 'playlist-modify-private', 'playlist-modify-public', 'user-follow-modify', ], 'state' => $state, ];
前端实现脚本:
<script> // Autocomplete for playlist lookup (step 1 of form) $(function() { $("#playlist-link").autocomplete({ source: function(request, response) { // Replace with your Spotify API access token const accessToken = "<?php echo $_SESSION['access_token'] ?>"; $.ajax({ url: "https://api.spotify.com/v1/search", headers: { "Authorization": "Bearer " + accessToken }, data: { q: request.term, type: "playlist", limit: 10 // Adjust the number of results as needed }, success: function(data) { // Can I delete the 'items' rows that are null here? If so, how?? if (data.playlists && data.playlists.items) { const playlists = data.playlists.items.map(function(playlist) { return { label: playlist.name, // Displayed in the autocomplete list value: playlist.name, // Value inserted into the input field id: playlist.id, // Store the playlist ID for later use images: playlist.images, // store images for display owner: playlist.owner.display_name // store owner name }; }); response(playlists); } else { response([]); // Return an empty array if no results are found } }, error: function(xhr, status, error) { console.error("Spotify API error:", error); response([]); // Handle errors gracefully } }); }, minLength: 3, // Start searching after 3 characters select: function(event, ui) { // Handle the selected playlist (e.g., store the ID) console.log("Selected playlist ID:", ui.item.id); // You can store the playlist ID in a hidden field or use it directly $("#playlist-id").val(ui.item.id); // Example: storing in a hidden input }, open: function() { // Style the dropdown list (optional) $(".ui-autocomplete").css("z-index", 1000); // Ensure it's on top }, focus: function(event, ui) { // Prevent the default behavior (inserting the value on focus) event.preventDefault(); } }).autocomplete("instance")._renderItem = function(ul, item) { // Custom rendering of each item in the dropdown const image = item.images && item.images.length > 0 ? item.images[0].url : "placeholder.jpg"; // Use a placeholder if no image return $("<li>") .append( "<div>" + "<img src='" + image + "' style='width: 50px; height: 50px; margin-right: 10px; vertical-align: middle;'/>" + "<span style='vertical-align: middle;'>" + item.label + "</span>" + "<br> <span style='font-size: 12px; color: grey; vertical-align: middle;'>By: " + item.owner + "</span>" + "</div>" ) .appendTo(ul); }; }); </script>
控制台报错截图:
解决方案
在map处理数组前,使用filter方法过滤掉空对象及缺少关键属性的项,同时给可选属性设置兜底值,彻底避免报错。
修改后的核心代码片段
success: function(data) { if (data.playlists && data.playlists.items) { // 过滤无效项:排除空对象,同时校验必须的name、id、owner属性 const validPlaylists = data.playlists.items.filter(playlist => { return playlist && playlist.name && playlist.id && playlist.owner; }); const playlists = validPlaylists.map(function(playlist) { return { label: playlist.name, value: playlist.name, id: playlist.id, images: playlist.images || [], // 兜底空数组,避免后续length访问报错 owner: playlist.owner.display_name || 'Unknown' // 兜底默认名称 }; }); response(playlists); } else { response([]); } }
优化说明
- 过滤逻辑:
filter方法先排除null/undefined的项,再校验name、id、owner这些后续必须用到的属性,确保所有进入map的项都是有效的 - 兜底处理:给
images设置默认空数组,防止后续item.images.length报错;给owner.display_name设置Unknown默认值,避免用户未公开名称时显示异常
内容的提问来源于stack exchange,提问作者Antonio Romo
相关产品推荐
相关产品推荐

